1

我看过像 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
}

有没有更好的办法?

4

1 回答 1

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正在监听的函数。然后,如果/profileurl 位于任一路由的末尾,则将捕获它并showProfile在 profileRouter 上运行该函数。

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

更新示例:

  • 如果用户导航到/game/:id它将调用defaultRouter > showGamewith param :id
  • 如果用户导航到/game/:id/profile它将调用defaultRouter > showGamewith param :id。它也会调用profileRouter > showProfile但没有参数(即它不会从 /game/:id 根目录发送 :id )。
于 2013-05-22T04:48:40.600 回答