【问题标题】:Preventing page navigation inside a Backbone-driven SPA防止在 Backbone 驱动的 SPA 中进行页面导航
【发布时间】:2015-03-04 12:52:21
【问题描述】:

理由

在我的 BB 应用程序中,我允许来自用户的快速输入,这些输入会在后台定期排队并发送到服务器。我目前遇到的问题是,如果用户离开页面,他们实际上会丢弃队列中的任何未决更改。

所以基本上我想做的是在用户离开之前通知他们,让他们有机会等待更改被保存,而不仅仅是退出和丢弃。

细节

因此,对于用户刷新或尝试导航到外部 URL 的一般情况,我们可以处理onbeforeunload 事件。当我们处于 SPA 的上下文中时,它变得有点棘手,因此在页面之间切换不会导致页面刷新。

我的直接想法是为所有锚点使用全局单击事件处理程序,并验证我是否要允许单击,这将适用于站点内链接导航。然而,这失败的地方是通过浏览器的后退/前进按钮导航。

我还查看了Backbone.routefilter,乍一看似乎正是我需要的。但是,使用docs 中描述的简单案例,该路由仍在执行中。

问题

我们如何拦截 Backbone SPA 中所有场景的导航?

【问题讨论】:

    标签: backbone.js browser-history pushstate backbone-routing


    【解决方案1】:

    直接链接导航

    使用全局事件处理程序来捕获所有点击事件

    $(document).on('click', 'a[href^="/"]', function (e) {
        var href = $(e.currentTarget).attr('href');
        e.preventDefault();
        if (doSomeValidation()) {
            router.navigate(href, { trigger: true });
        }
    });
    

    页面刷新/外部网址导航

    处理window上的onbeforeunload事件

    $(window).on('beforeunload', function (e) {
        if (!doSomeValidation()) {
            return 'Leaving now will may result in data loss';
        }
    });
    

    浏览器后退/前进按钮导航

    在幕后Backbone.Router 使用Backbone.history 最终利用HTML5 pushstate API。根据您传递给Backbone.history.start 的选项以及您的浏览器的功能,API 将挂钩onhashchange 事件或onpopstate 事件。

    深入研究Backbone.history.start 的源代码,很明显无论您是否使用推送状态,都使用相同的事件处理程序,即checkUrl

    if (this._hasPushState) {
        addEventListener('popstate', this.checkUrl, false);
    } else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
        addEventListener('hashchange', this.checkUrl, false);
    } else if (this._wantsHashChange) {
        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
    }
    

    因此,我们可以覆盖此方法并在其中执行验证

    var originalCheckUrl = Backbone.history.checkUrl;
    Backbone.history.checkUrl = function (e) {
        if (doSomeValidation()) {
            return originalCheckUrl.call(this, e);
        } else {
            // re-push the current page into the history (at this stage it's been popped)
            window.history.pushState({}, document.title, Backbone.history.fragment);
            // cancel the original event
            return false;
        }
    };
    

    【讨论】:

      猜你喜欢
      • 2018-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-18
      相关资源
      最近更新 更多