【问题标题】:Good pattern for doing additive routes in Backbone在 Backbone 中进行附加路由的良好模式
【发布时间】:2013-05-21 22:42:24
【问题描述】:

我研究过类似 BackboneMVC 和 Backbone Marionette 中的子路由想法。 我想我正在寻找一些不同的东西。 有没有人想出好的模式,不是子路由,而是附加路由?

例如,您有一个可以在任何屏幕上显示的大型配置文件灯箱。您想将其添加到浏览器历史记录并让 url 能够重新创建它。所以你可能有这些网址:

'dashboard/lightbox/profile'
'game/3/lightbox/profile'

在第一个路由中,它应该为dashboard 路由执行所有行为,然后为附加的lightbox/profile 路由应用行为。这样,灯箱打开,仪表板在后台。 在第二种情况下,它应该类似地执行game/3 路由的所有行为,然后在其上打开灯箱。

这是任何人都听说过或实施的模式吗? 我想不出不使用 splats 的方法,像这样:

routes: {
  'dashboard/*path': 'showDashboard',
  'game/:id/*path': 'showGame'
},
showDashboard: function(path) {
  //Show the dash
  this._checkIfLightboxShouldOpen(path)
},
showGame: function(id, path) {
  //Show the correct game based on id
  this._checkIfLightboxShouldOpen(path)
},
_checkIfLightboxShouldOpen(path) {
  // Parse the path string for lightbox behaviors
}

有没有更好的办法?

【问题讨论】:

    标签: backbone.js architecture routing marionette backbone-routing


    【解决方案1】:

    我最近的一个项目需要这个,我计划在某个时候将这个代码作为开源发布,但你可以这样做:

    创建一个全局路由器来处理所有路由:

    App.GlobalRouter = Backbone.Router.extend({
        initialize: function(){
            this._routes = {};
        },
    
        registerRoute: function(route, rootRoute){
        var rootName;
    
        if(rootRoute) {
            route = rootRoute + '/' + route;
            rootName = this.registerRoute(rootRoute);
        }
    
        if(!_.isRegExp(route))
            route = this._routeToRegExp(route);
    
            var name = this._routes[route] ? this._routes[route] : _.uniqueId('r');
            this._routes[route] = name;
    
            this.route(route, name, function(){});
    
            if(rootName) {
                this.on('route:'+name, function(){
                    var args = slice(arguments);
                    this.trigger.apply(this, ['route:' + rootName].concat(args));
                }.bind(this));
            }
    
            return name;
        }
    });
    

    然后创建一个:

    App.globalRouter = new App.GlobalRouter();
    

    然后创建一个修改后的路由器来扩展您的所有路由器:

    App.Router = Backbone.Router.extend({
        constructor: function (options){
            options = options || {};
            if(options.root) this.root = options.root;
            this.globalRouter = App.globalRouter;
    
            Backbone.Router.apply(this, [options]);
        },
    
        route: function(route, name, callback, root){
            if(!App.globalRouter) return false;
    
            // If callback is root param
            if(callback && !_.isFunction(callback)) {
                root = callback;
                callback = null;
            }
    
            // If no name is callback param.
            if(_.isFunction(name)) {
                callback = name;
                name = '';
            }
    
            if(!callback)
                callback = this[name];
    
            var router = this;
            var roots = root || this.root;
            if(roots && !_.isArray(roots)) roots = [roots];
    
            if(roots) {
                _.each(roots, function(root){
                    var globalName = App.globalRouter.registerRoute(route, root);
                    router.listenTo(App.globalRouter, 'route:'+globalName, function(){
                        var args = slice(arguments);
                        var callbackArgs = args.slice(callback && -callback.length || 0);
                        callback && callback.apply(router, callbackArgs);
                        router.trigger.apply(router, ['route:' + name].concat(callbackArgs));
                        router.trigger('route', name, callbackArgs);
                    });
                });
            } else {
                var globalName = App.globalRouter.registerRoute(route);
                router.listenTo(App.globalRouter, 'route:'+globalName, function(){
                    var args = slice(arguments);
                    var callbackArgs = args.slice(callback && -callback.length || 0);
                    callback && callback.apply(router, callbackArgs);
                    router.trigger.apply(router, ['route:'+name].concat(callbackArgs));
                    router.trigger('route', name, callbackArgs);
                });
            }
    
            return this;
        }
    });
    

    从这里您可以创建所需的尽可能多的路由器并将它们注册在同一路由上,您也可以创建一个具有要监听的路由路由的路由器,因此在您的情况下,您可能有 2 或 3 个路由器,这里是你可以做的一个例子:

    var defaultRouter = App.Router.extend({
       routes: {
           'dashboard': 'showDashboard',
           'game/:id': 'showGame'
       },
       showDashboard: function() {},
       showGame: function(id) {},
    });
    
    var profilerRouter = App.Router.extend({
       root: [
           'dashboard',
           'game/:id'
       ],
       routes: {'profile', 'showProfile'},
       showProfile: function(){//Show lightbox}
    });
    

    这将侦听/dashboard/game/:id 并在defaultRouter 上调用该函数正在侦听。然后,如果 /profile 位于任一路由的 url 末尾,则将捕获它并在 profileRouter 上运行 showProfile 函数。

    注意:我已经快速修改了我项目中的代码以更改一些名称/命名空间问题,因此您可能需要检查我没有遗漏任何内容,但代码应该是正确的,否则

    更新示例:

    • 如果用户导航到/game/:id,它将使用参数:id 调用defaultRouter > showGame
    • 如果用户导航到/game/:id/profile,它将使用参数:id 调用defaultRouter > showGame。它还会调用profileRouter > showProfile,但没有参数(即它不会从 /game/:id 根目录发送 :id)。

    【讨论】:

    • 我想我在这里遗漏了关键的洞察力——这是抓住/ 之前的第一件事以及使用该正则表达式的任何参数,然后传递到叶路由吗?跨度>
    • 是的,完全!它回答了更大的问题,即这是否已经存在。我很惊讶它没有,我认为这将是一个普遍的需求。似乎是图书馆的绝佳候选人。不过,围绕这种行为编写测试让我很费解。
    • @SimpleAsCouldBe 如果您给我发电子邮件(电子邮件在我的个人资料中),我现在可以将测试套件发送给您,我计划在接下来的几周内将其作为库发布,一旦我下班了……
    猜你喜欢
    • 2013-07-12
    • 1970-01-01
    • 2013-02-12
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    相关资源
    最近更新 更多