Backbone.js 在主干网中执行加法路由的良好模式

Backbone.js 在主干网中执行加法路由的良好模式,backbone.js,architecture,routing,marionette,backbone-routing,Backbone.js,Architecture,Routing,Marionette,Backbone Routing,我已经研究过BackboneMVC和主干木偶中的子程序思想。 我想我在寻找一些不同的东西。 有没有人想出好的模式,不是子例程,而是加法路由 比如说,你有一个可以在任何屏幕上显示的大轮廓灯箱。您希望将其添加到浏览器历史记录中,并使url能够重新创建它。因此,您可能有以下URL: 'dashboard/lightbox/profile' 'game/3/lightbox/profile' 在第一个路由中,它应该执行仪表板路由的所有行为,然后为添加的lightbox/profile路由应用行为。这样

我已经研究过BackboneMVC和主干木偶中的子程序思想。 我想我在寻找一些不同的东西。 有没有人想出好的模式,不是子例程,而是加法路由

比如说,你有一个可以在任何屏幕上显示的大轮廓灯箱。您希望将其添加到浏览器历史记录中,并使url能够重新创建它。因此,您可能有以下URL:

'dashboard/lightbox/profile'
'game/3/lightbox/profile'
在第一个路由中,它应该执行
仪表板
路由的所有行为,然后为添加的
lightbox/profile
路由应用行为。这样,lighbox将打开,仪表板位于后台。 在第二种情况下,它应该类似地执行
游戏/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
}

有更好的方法吗?

我在最近的一个项目中需要它,我计划在某个时候以开源的形式发布这段代码,但您可以这样做:

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
}
创建全局路由器以处理所有路由:

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末尾,则将捕获该url并在profileRouter上运行
showProfile
功能

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

更新示例:

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

我在最近的一个项目中需要这段代码,我计划在某个时候以开源的形式发布这段代码,但您可以这样做:

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
}
创建全局路由器以处理所有路由:

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末尾,则将捕获该url并在profileRouter上运行
showProfile
功能

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

更新示例:

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

我想我错过了关键的洞察——这是不是在
/
和任何使用regexp的参数之前抓取第一件事,然后再传递到叶路由?是的,完全是!它回答了一个更大的问题,即这是否已经存在。我很惊讶它没有,我想这将是一个共同的需要。似乎是图书馆的理想人选。尽管如此,围绕这种行为编写测试还是让我心力交瘁。@simpleascould如果你给我发电子邮件(电子邮件在我的个人资料中),我现在可以给你发送测试套件,我计划在未来几周内将其作为库发布,一旦我下班了……我想我错过了这里的关键点——这是不是在
/
和任何使用regexp的参数之前先抓取第一件事,然后再传递到leaf routes?是的,完全正确!它回答了一个更大的问题,即这是否已经存在。我很惊讶它没有,我想这将是一个共同的需要。似乎是图书馆的理想人选。尽管如此,围绕这种行为编写测试还是让我心力交瘁。@simpleascould如果你给我发电子邮件(电子邮件在我的个人资料中),我现在可以给你发送测试套件,我计划在接下来的几周内,一旦我下班了,就把它作为一个库发布。。。