我目前正在使用Backbone.Marionette创建SPA,在其中一个视图中,用户可以使用未保存的更改进行导航。我可以控制其中一些事件,比如视图中的按钮和菜单选项会将用户带走,但是其他一些事件需要操作Backbone.Router或直接使用DOM事件。
我已经尝试收听beforeunload
(因为应用程序仍然加载而无法正常工作)和hashchange
(因为无法阻止浏览器导航而无法正常工作) 。这些解决方案(1,2,3)在这种情况下不起作用,Javascript永远不会被卸载。
更改Backbone.Router似乎是最好的选择,但由于它是如何初始化的,我不认为有可能引入这个功能,或者至少我找不到这样做的方法。例如,This solution无效,因为hashchange
无法取消(您无法在其上调用stopPropagation),而this other solution无法正常工作,因为navigate
在Backbone.Router对象上没有定义。
有什么建议吗?
答案 0 :(得分:1)
我已经设法找到了解决方案,但还需要做一些工作。对于这个解决方案,我假设您在视图变脏时跟踪。
退出视图有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()
}
}
<强> 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上的代码覆盖,但有一个我无法弄清楚的问题,我将为它创建另一个问题
当回击/前进时,浏览器会在调用路由器之前更改地址栏,因此最终会出现不一致的状态:地址栏显示与应用程序状态不同的路径。这是一个大问题,如果用户再次点击后退按钮,保存或放弃更改后,她将被带到另一条路线,而不是之前的路线。
其他一切正常,它显示一个弹出窗口询问用户是否要离开或继续,如果用户选择留下,则不会重新加载视图。