在pushState单页面应用程序中使用URL片段(#)作为模态视图

时间:2014-02-13 15:15:33

标签: javascript backbone.js url-routing single-page-application pushstate

我们在仅限状态模式下使用Backbone.Router,因此所有客户端路由都是无哈希
但是,我们在应用程序中实现模态视图时遇到了困难。

挑战如下:

  • 我们希望Back按钮隐藏当前的模态视图(所以我们需要它有一个URL);
  • 我们希望转发再次显示,而不重新绘制整个应用程序;
  • 我们希望能够在“任何现有路线之上”而不仅仅在一个页面上显示模态;
  • 我们希望能够制作立即显示特定模式的链接(例如登录模态视图)。

换句话说,我们希望模式视图在历史记录中表示

我们的第一次尝试是使用/login之类的URL作为登录模式,并在route处理程序中专门处理它们。当我们在/otherpage时,打开模式将导航到/login,当模态关闭时,再次导航到/otherpage

但是,这有一个非常严重的问题:像/login这样的网址“不知道”应该在哪个视图上绘制,因此我们必须在按下后退和前进时重新绘制所有内容。

这实际上是有道理的:主屏幕上的登录模式应该具有与其他页面上的登录模式不同的URL。

我的第二个想法是也许我们可以使用哈希来表示当前的模态视图

/
/#login
/otherpage
/otherpage#login

这使路由处理程序变得简单:

  • 首先,根据匹配的路线绘制实际视图,就像我们之前一样。
  • 之后,如果存在哈希,则在顶部显示模态视图。

这也符合哈希是可见文档的“片段”的想法。 (是的,应用程序不是文档,bla bla bla。我们仍然希望它们可以被寻址。)

这种方法有任何固有的问题吗? 是否有更好的方法来满足我们的条件?

1 个答案:

答案 0 :(得分:2)

如果我理解你的问题,我不相信你需要哈希,我相信你可以通过简单地添加更多的路线来实现模态。如果您需要支持其他现有路由的登录模式,只需添加另一条路径即可将登录添加到结尾。这是一个例子:

var Login = Backbone.Model.extend({
    closeLogin: function () {
        this.set({ open: false }, { silent: true });
        this.trigger('loginClosed');
    }
});

var LoginView = Backbone.View.extend({
    el: '#loginModal',     
    initialize: function () {
        this.listenTo(this.model, 'loginClosed', this.closeLogin);
    },
    closeLogin: function () {
        // do whatever you would normally do to close the modal
    }
});

var Router = Backbone.Router.extend({
    routes: {
        '/login': 'defaultRouteLogin',
        '': 'defaultRoute',
        'otherpage/login': 'otherPageRouteLogin',
        'otherpage': 'otherPageRoute'
    },
    defaultRoute: function () {
        // defaultRoute behaviors
        this.login.closeLogin();
    },
    defaultRouteLogin: function () {
        // defaultRoute behavior
        // instantiate login modal
    },
    otherPageRoute: function () {
        // otherPageRoute behavior
        this.login.closeLogin();
    },
    otherPageRouteLogin: function () {
        // otherPageRoute behavior
        // instantiate login modal
    },
    initialize: function () {
        this.login = new Login();
        this.loginView = new LoginView({ model: this.login });
    }
});

要支持后退按钮行为,请使用在每个可以打开模式的路径上关闭登录模式的方法。请务必正确订购路线。