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对象上定义.
有什么建议?
我已经设法找到解决方案,尽管还需要做更多的工作。对于这个解决方案,我假设您在视图脏时进行跟踪。
移出视图的主要方式有 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 的代码中,但有一个问题我无法弄清楚,我将为其创建另一个问题。
当点击后退/前进时,浏览器会在调用路由器之前更改地址栏,因此最终会出现不一致的状态:地址栏显示到应用程序状态的不同路由。这是一个大问题,如果用户再次单击后退按钮,在保存或放弃更改后,她将被带到另一条路线,而不是之前的路线。
其他一切工作正常,它会显示一个弹出窗口,询问用户是否要离开或继续,并且如果用户选择留下,则不会重新加载视图。