如果内容未保存,则阻止导航到另一个视图

fwi*_*tra 12 javascript backbone.js

我们有一个backbone.js应用程序,它向用户显示许多表单.我们想要的是非常简单:如果用户转到另一个页面而不保存填写的表单,我们想要显示一个确认对话框.

在经典形式中,这很容易,只需在jQuerysh中实现window.onbeforeunload(或$(window).on('beforeunload')).但骨干应用程序通常只有一个视图.我尝试使用onHashChange,但在该回调中返回false并不会阻止Backbone仍然转到另一个视图.

指针表示赞赏.搜索互联网并没有找到任何有效的回复.

ggo*_*zad 6

我会避免使用Backbone进行攻击.您可以通过替换通常Backbone.history以类似的方式开始的部分来全局地为所有链接执行此操作

initRouter: function () {
    Backbone.history.start({ pushState: true });
    $(document).on('click', 'a', function (ev) {
        var href = $(this).attr('href');
        ev.preventDefault();
        if (changesAreSaved) {
            router.navigate(href, true);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

当然,您需要更换changesAreSaved有意义的内容并添加有关处理链接的其他任何登录信息.


Den*_*app 6

我也会破解Backbone.history.loadUrl,这就是加载路由回调的地方.

// ALLOW PREVENTING HASH NAVIGATION

var originalFn = Backbone.history.loadUrl;

Backbone.history.loadUrl = function() {
    // I introduced an application state variable, but it can be solved in multiple ways
    if (app && app.states.isNavigationBlocked) {
        var previousFragment = Backbone.history.fragment;
        window.location.hash = '#' + previousFragment;
        return false;
    }
    else {
        return originalFn.apply(this, arguments);
    }
};
Run Code Online (Sandbox Code Playgroud)

说明:

1)

Backbone监听hashchange事件并设置Backbone.history.checkUrl为回调:https: //github.com/jashkenas/backbone/blob/1.1.2/backbone.js#L1414

Backbone.$(window).on('hashchange', this.checkUrl);
Run Code Online (Sandbox Code Playgroud)

2)

Backbone.history.checkUrl 检查哈希是否已更改并调用 Backbone.history.loadUrl

checkUrl: function(e) {
  var current = this.getFragment();
  if (current === this.fragment && this.iframe) {
    current = this.getFragment(this.getHash(this.iframe));
  }
  if (current === this.fragment) return false;
  if (this.iframe) this.navigate(current);
  this.loadUrl();
},
Run Code Online (Sandbox Code Playgroud)

3)

Backbone.history.loadUrl 找到第一个匹配的路由并调用其回调:

loadUrl: function(fragment) {
  fragment = this.fragment = this.getFragment(fragment);
  return _.any(this.handlers, function(handler) {
    if (handler.route.test(fragment)) {
      handler.callback(fragment);
      return true;
    }
  });
},
Run Code Online (Sandbox Code Playgroud)

实用说明:

Backbone.history.fragment存储当前哈希,它已设置Backbone.history.loadUrl,因此我们可以在hashchange事件发生后访问它,但在路由器回调完成之前.


Oll*_*liM 5

我想你可以破解Backbone.history.loadUrl(http://documentcloud.github.com/backbone/docs/backbone.html#section-137).我做了一个快速测试,每次更改页面时,此代码都会进行检查.您只想在有实际原因的情况下添加代码才能激活检查.

var goingBack = false;
function doCheck() {
  // TODO: add code that checks the app state that we have unsaved data
  return goingBack || window.confirm("Are you sure you want to change pages?");
}

var oldLoad = Backbone.History.prototype.loadUrl;
Backbone.History.prototype.loadUrl = function() {
  if(doCheck()) {
    return oldLoad.apply(this, arguments);
  } else {
    // change hash back
    goingBack = true;
    history.back();
    goingBack = false;
    return true;
  }
}
Run Code Online (Sandbox Code Playgroud)

您还必须处理window.onbeforeunload,因为用户可能仍然完全离开页面.