使用Backbone,我能否获得当前路线的名称?我知道如何绑定到路线更改事件,但是我希望能够在其他时间确定更改之间的当前路线。
使用Backbone,我能否获得当前路线的名称?我知道如何绑定到路线更改事件,但是我希望能够在其他时间确定更改之间的当前路线。
Answers:
如果您已在应用程序中实例化了路由器,则以下行将返回当前片段:
Backbone.history.getFragment();
“ [...]历史记录充当全局路由器(每帧),以处理hashchange事件或pushState,匹配适当的路由并触发回调。您不必自己创建其中的一个- 您应该使用引用到Backbone.history,如果您使用带有路由的路由器,则会自动为您创建。[...]“
如果需要绑定到该片段的函数的名称,则可以在Router范围内进行如下操作:
alert( this.routes[Backbone.history.getFragment()] );
或从路由器外部这样:
alert( myRouter.routes[Backbone.history.getFragment()] );
Backbone.history.getFragment()
,因为Backbone.history.fragment
它是私有的隐藏属性。
罗伯特的答案很有趣,但可悲的是,只有在哈希值完全符合路由定义的情况下,它才有效。例如,如果您有一条路线,user(/:uid)
则如果Backbone.history.fragment
是"user"
或则不匹配"user/1"
(两者都是该路线的两个最明显的用例)。换句话说,只有在哈希完全正确"user(/:uid)"
(极不可能)的情况下,它才会找到适当的回调名称。
由于我需要此功能,因此我Backbone.Router
使用current
- 函数扩展了-功能,该功能可复用一些历史和路由器对象用来将当前片段与定义的Routes相匹配的代码,以触发适当的回调。在我的用例中,它采用了可选参数route
,如果将其设置为true,则将返回为路由定义的相应函数名称。否则,它将从返回当前的哈希片段Backbone.History.fragment
。
您可以将代码添加到现有的Extend中,以在其中初始化和设置Backbone路由器。
var Router = new Backbone.Router.extend({
// Pretty basic stuff
routes : {
"home" : "home",
"user(:/uid)" : "user",
"test" : "completelyDifferent"
},
home : function() {
// Home route
},
user : function(uid) {
// User route
},
// Gets the current route callback function name
// or current hash fragment
current : function(route){
if(route && Backbone.History.started) {
var Router = this,
// Get current fragment from Backbone.History
fragment = Backbone.history.fragment,
// Get current object of routes and convert to array-pairs
routes = _.pairs(Router.routes);
// Loop through array pairs and return
// array on first truthful match.
var matched = _.find(routes, function(handler) {
var route = handler[0];
// Convert the route to RegExp using the
// Backbone Router's internal convert
// function (if it already isn't a RegExp)
route = _.isRegExp(route) ? route : Router._routeToRegExp(route);
// Test the regexp against the current fragment
return route.test(fragment);
});
// Returns callback name or false if
// no matches are found
return matched ? matched[1] : false;
} else {
// Just return current hash fragment in History
return Backbone.history.fragment
}
}
});
// Example uses:
// Location: /home
// console.log(Router.current()) // Outputs 'home'
// Location: /user/1
// console.log(Router.current(true)) // Outputs 'user'
// Location: /user/2
// console.log(Router.current()) // Outputs 'user/2'
// Location: /test
// console.log(Router.current(true)) // Outputs 'completelyDifferent'
我确定可以进行一些改进,但这是一个入门的好方法。同样,无需扩展Route对象即可轻松创建此功能。我这样做是因为这是我设置的最方便的方法。
我尚未对此进行全面测试,所以请让我知道是否有任何问题。
我对该函数进行了一些更改,因此我返回了一个带有片段,参数和路由的对象,而不是返回哈希或路由回调名称,因此您可以访问当前路由中的所有数据,就像从路由中那样:事件。
您可以看到以下更改:
current : function() {
var Router = this,
fragment = Backbone.history.fragment,
routes = _.pairs(Router.routes),
route = null, params = null, matched;
matched = _.find(routes, function(handler) {
route = _.isRegExp(handler[0]) ? handler[0] : Router._routeToRegExp(handler[0]);
return route.test(fragment);
});
if(matched) {
// NEW: Extracts the params using the internal
// function _extractParameters
params = Router._extractParameters(route, fragment);
route = matched[1];
}
return {
route : route,
fragment : fragment,
params : params
};
}
请参阅前面的代码以获取更多注释和解释,它们看起来大致相同。
_.find
为this
,从而消除了对Router
变量的需要(@DanAbramov已经做到了)。
Marionette.AppRouter
,上面的功能,但替补延长你的路由器Router.appRoutes
的Router.routes
。
这里有一个稍微更详细的(或者,取决于你的口味,更易读)的版本西蒙的回答:
current: function () {
var fragment = Backbone.history.fragment,
routes = _.pairs(this.routes),
route,
name,
found;
found = _.find(routes, function (namedRoute) {
route = namedRoute[0];
name = namedRoute[1];
if (!_.isRegExp(route)) {
route = this._routeToRegExp(route);
}
return route.test(fragment);
}, this);
if (found) {
return {
name: name,
params: this._extractParameters(route, fragment),
fragment: fragment
};
}
}
如果您查看的来源Router
,您会看到当路由器触发事件说发生了某些变化时,它将通过名称传递它为“ route:name”。
http://documentcloud.github.com/backbone/docs/backbone.html#section-84
您始终可以在路由器上挂接“ route”事件,并将其存储以获取当前路由。
route
,如果事件trigger
没有 true
(建议与默认)。