阻止用户使用未保存的更改进行导航

Jay*_*ayC 5 javascript jquery backbone.js

我目前正在使用Backbone.Marionette来创建SPA,在其中一个视图中,用户可以使用未保存的更改进行导航.我可以控制其中一些事件,例如视图中的按钮和菜单选项,这会将用户带走,但是其他一些事件需要操作Backbone.Router或直接使用DOM事件.

我已经尝试过监听beforeunload(因为应用程序仍然加载hashchange不起作用)和(不起作用,因为你无法阻止浏览器导航).这些解决方案(1,2,3)不要在这种情况下工作时,JavaScript是永远不会卸载.

改变Backbone.Router似乎是最好的选择,但由于它是如何初始化的,我认为不可能引入这个功能,或者至少我找不到这样做的方法.例如,此解决方案不起作用,因为hashchange不可取消(您不能在其上调用stopPropagation),并且此其他解决方案不起作用,因为navigate未在Backbone.Router对象上定义.

有什么建议?

Jay*_*ayC 1

我已经设法找到解决方案,尽管还需要做更多的工作。对于这个解决方案,我假设您在视图脏时进行跟踪。

移出视图的主要方式有 4 种:

  1. 单击视图上的链接
  2. 单击视图外的链接
  3. 单击刷新或外部链接
  4. 单击浏览器上的后退/前进

1.申请链接

这是最简单的情况。当你点击自己的链接时,你必须检查你的视图是否是脏的。例如,我有一个由historyBack函数处理的应用内后退按钮。论观点:

historyBack: function() {
    if (this.isDirty) {
         answer = confirm("There are unsaved changes.\n\nDo you wish to continue?")

        if (answer) {
            this.isDirty = false
            window.history.back()
        }
    }

    else {
        window.history.back()
    }
}
Run Code Online (Sandbox Code Playgroud)

2. 在你的视野之外的链接

这种类型的交互可以通过扩展 Router 原型的execute方法来处理,而不是navigate其他地方提出的方法。

应该有一个可由路由器访问的变量来存储视图的状态。就我而言,我使用路由器本身,并且每次更改视图上的脏标志时都会更新此变量。

代码应该如下所示:

_.extend(Backbone.Router.prototype, {

    execute: function (callback, args, name) {
        if (Backbone.Router.isDirty) {
            answer = confirm "There are unsaved changes.\n\nDo you wish to continue?";

            if (!answer) {
                return false;
            }
        }

        Backbone.Router.isDirty = false
        if (callback) callback.apply(this, args) 
    }
}
Run Code Online (Sandbox Code Playgroud)

3.刷新或外部链接

刷新和外部链接实际上会卸载您的Javascript,因此这里基于beforeunload(参见问题)的解决方案实际上有效。无论您在何处管理视图,我都会使用控制器,但假设它位于同一视图上,您​​在显示时添加一个侦听器并在销毁时将其删除:

onShow: function() {
    $(window).bind("beforeunload", function (e) {
        if (this.isDirty) {
             return "There are unsaved changes.";
        }
    }
}

onDestroy: function() {
    $(window).unbind("beforeunload");
}
Run Code Online (Sandbox Code Playgroud)

4. 在浏览器上后退/前进

这是最棘手的情况,也是我还没有完全弄清楚的情况。当点击后退/前进时,用户可以导航出应用程序或在应用程序内,这两种情况都包含在 1 和 3 的代码中,但有一个问题我无法弄清楚,我将为其创建另一个问题。

当点击后退/前进时,浏览器会在调用路由器之前更改地址栏,因此最终会出现不一致的状态:地址栏显示到应用程序状态的不同路由。这是一个大问题,如果用户再次单击后退按钮,在保存或放弃更改后,她将被带到另一条路线,而不是之前的路线。

其他一切工作正常,它会显示一个弹出窗口,询问用户是否要离开或继续,并且如果用户选择留下,则不会重新加载视图。