Backbone.js 在主干网中执行加法路由的良好模式
我已经研究过BackboneMVC和主干木偶中的子程序思想。 我想我在寻找一些不同的东西。 有没有人想出好的模式,不是子例程,而是加法路由 比如说,你有一个可以在任何屏幕上显示的大轮廓灯箱。您希望将其添加到浏览器历史记录中,并使url能够重新创建它。因此,您可能有以下URL: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路由应用行为。这样
'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
功能
注意:我已经快速修改了从项目中提取的代码,以更改一些名称/命名空间问题,因此您可能需要检查我是否遗漏了任何内容,否则代码应该是正确的
更新示例:
- 如果用户导航到
,它将使用param/game/:id
调用:id
defaultRouter>showGame
- 如果用户导航到
,它将使用参数/game/:id/profile
调用:id
。它还将调用defaultRouter>showGame
,但不带参数(即,它不从/game/:id根目录发送:id)profileRouter>showProfile
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
功能
注意:我已经快速修改了从项目中提取的代码,以更改一些名称/命名空间问题,因此您可能需要检查我是否遗漏了任何内容,否则代码应该是正确的
更新示例:
- 如果用户导航到
,它将使用param/game/:id
调用:id
defaultRouter>showGame
- 如果用户导航到
,它将使用参数/game/:id/profile
调用:id
。它还将调用defaultRouter>showGame
,但不带参数(即,它不从/game/:id根目录发送:id)profileRouter>showProfile
/
和任何使用regexp的参数之前抓取第一件事,然后再传递到叶路由?是的,完全是!它回答了一个更大的问题,即这是否已经存在。我很惊讶它没有,我想这将是一个共同的需要。似乎是图书馆的理想人选。尽管如此,围绕这种行为编写测试还是让我心力交瘁。@simpleascould如果你给我发电子邮件(电子邮件在我的个人资料中),我现在可以给你发送测试套件,我计划在未来几周内将其作为库发布,一旦我下班了……我想我错过了这里的关键点——这是不是在/
和任何使用regexp的参数之前先抓取第一件事,然后再传递到leaf routes?是的,完全正确!它回答了一个更大的问题,即这是否已经存在。我很惊讶它没有,我想这将是一个共同的需要。似乎是图书馆的理想人选。尽管如此,围绕这种行为编写测试还是让我心力交瘁。@simpleascould如果你给我发电子邮件(电子邮件在我的个人资料中),我现在可以给你发送测试套件,我计划在接下来的几周内,一旦我下班了,就把它作为一个库发布。。。