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

时间:2015-11-10 10:54:30

标签: javascript jquery backbone.js

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

我已经尝试收听beforeunload(因为应用程序仍然加载而无法正常工作)和hashchange(因为无法阻止浏览器导航而无法正常工作) 。这些解决方案(123)在这种情况下不起作用,Javascript永远不会被卸载。

更改Backbone.Router似乎是最好的选择,但由于它是如何初始化的,我不认为有可能引入这个功能,或者至少我找不到这样做的方法。例如,This solution无效,因为hashchange无法取消(您无法在其上调用stopPropagation),而this other solution无法正常工作,因为navigate在Backbone.Router对象上没有定义。

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

我已经设法找到了解决方案,但还需要做一些工作。对于这个解决方案,我假设您在视图变脏时跟踪。

退出视图有4种主要方式;

  1. 点击视图上的链接
  2. 点击视图外的链接
  3. 点击刷新或外部链接
  4. 点击浏览器上的后退/前进
  5. <强> 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()
        }
    }
    

    <强> 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) 
        }
    }
    

    第3。刷新或外部链接

    刷新和外部链接实际上卸载了您的Javascript,所以这里基于beforeunload(请参阅问题)的解决方案实际上有效。无论你在哪里管理你的视图,我都使用一个控制器,但让我们假设它在同一个视图上,你在show上添加一个监听器并在destroy上删除它:

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

    <强> 4。在浏览器上后退/前进

    这是最棘手的案例,也是我尚未完全弄清楚的案例。当回击/向前,用户可以导航到应用程序或应用程序内,两个案例都被1和3上的代码覆盖,但有一个我无法弄清楚的问题,我将为它创建另一个问题

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

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