Backbone.js—;在触发路由之前/之后调用方法
我希望在我的Backbone.js路由器中触发路由之前和之后分别调用setup/teardown方法。有没有人创造了一种优雅的方式 您考虑过吗?包裹不是一个解决方案,例如,如果您有20条路线,您必须将它们全部包裹起来 但是你可以用元编程来实现这一点Backbone.js—;在触发路由之前/之后调用方法,backbone.js,routes,router,Backbone.js,Routes,Router,我希望在我的Backbone.js路由器中触发路由之前和之后分别调用setup/teardown方法。有没有人创造了一种优雅的方式 您考虑过吗?包裹不是一个解决方案,例如,如果您有20条路线,您必须将它们全部包裹起来 但是你可以用元编程来实现这一点 class Backbone.FlexRouter extends Backbone.Router route: (route, name, handler) -> super route, name, -> @t
class Backbone.FlexRouter extends Backbone.Router
route: (route, name, handler) ->
super route, name, ->
@trigger "route:before"
handler()
@trigger "route:after"
UPD:我相信JS应该是这样的(但我没有测试过)
这个插件做你想要的。它适用于0.5.3。我不确定它是否适用于0.9.1
阿列克谢的回答几乎是对的,但也有一些微妙的地方没有提到
class ApplicationRouter extends Backbone.Router
route: (route, name, callback = null) ->
callback = @[name] if ! callback
super route, name, ->
@trigger 'route:before'
result = callback && callback.apply(@, arguments)
@trigger 'route:after'
return result
我之前遇到过这个问题,我想我会分享我的解决方案,将“中间件”插入主干路由流。目标是根据某些条件(例如,功能标志、会话处理等)将用户重新路由到各种流
Backbone.ProtectedRouter = Backbone.Router.extend({
/*
* Subclass of Router that monkeypatches route in order to protect certain
* routes.
*
* If you want to add a protected route, add it to the protectedRoutes
* object in this form:
* route: { method: fn, assertion: fn, args: [args..] }
*
* * method => the method to call if the assertion is true (the route should
* be protected in the given scenario)
*
* * assertion => the function that decides whether or not the route
* should be rendered
*
* * args => the arguments to be passed to method
*/
route: function(route, name, handler) {
var _this = this;
Backbone.Router.prototype.route(route, name, function(){
var boundHandler = _.bind(handler, _this),
attrs, method, args, dfd;
attrs = _.has(_this.protectedRoutes, route) ? _this.protectedRoutes[route] : null;
if ( attrs && !attrs.assertion() ) {
// In this scenario my flows all return Deferreds
// you can make this event based as well.
dfd = _this[attrs.method].apply(_this, attrs.args.concat([route]));
dfd.then(boundHandler);
} else
boundHandler.apply(_this, arguments);
});
}
});
从那里,您只需使用protectedRoutes
哈希扩展主干.ProtectedRouter
,如下所示:
var router = Backbone.ProtectedRouter.extend({
protectedRoutes: {
'home': {
assertion: function() { return is_logged_in; },
method: 'renderLogin',
args: ['some_arg']
}
},
routes: {
'home': 'renderHome'
},
...
});
在这种情况下,如果对home
路由发出请求并且已登录为false
,则调用renderLogin
方法并传递'some\u arg'
。在流之后,renderLogin
将返回一个已解析的延迟,该延迟导致调用原始处理程序(renderHome
)
我希望这有帮助。我也非常乐意接受建议!:) 我最近遇到了这种需求(检查用户是否经过身份验证)。不幸的是,主干网没有给我们一个前后事件,所以您需要覆盖或扩展Router.route。感觉不是很干净,因为您必须从源代码复制并在那里编辑,但这是我找到的唯一方法。下面是主干默认代码(1.0.0)并标记了我的自定义代码:
Backbone.Router.prototype.route = function(route, name, callback) {
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (_.isFunction(name)) {
callback = name;
name = '';
}
if (!callback) callback = this[name];
// here my custom code
callback = _.wrap(callback, _.bind(function(cb) {
if (name == 'login' || sessionModel.authenticated()) {
_.bind(cb, this)();
} else {
this.navigate('login', {trigger: true});
}
}, this));
// finish my custom code
var router = this;
Backbone.history.route(route, function(fragment) {
var args = router._extractParameters(route, fragment);
callback && callback.apply(router, args);
router.trigger.apply(router, ['route:' + name].concat(args));
router.trigger('route', name, args);
Backbone.history.trigger('route', router, name, args);
});
return this;
};
请注意.wrap
和.bind
因此这是您在使用路由器时所期望的。否则我会得到一个“这是未定义的”错误。Ethical Agnawl和Alexey都是正确的<代码>\ wrap
是正确的解决方案,但如果您有一堆路由,并以正常主干方式编写它们,那将是一件痛苦的事情。我意识到你可以做到:
var Pages = {}
Pages.loginPage = function(){ ... }
Pages.mainPage = function(){ ... }
_.map(Pages,function(func,name){
Pages[name] = _.wrap(func,function(funky){
// Save original arguments
var args = Array.prototype.slice.call(arguments,1);
// Do stuff before the route
funky(args);
// Do stuff after the route
});
});
var myRouter = Backbone.Router.extend({
routes: ... /* as usual */
}).extend(Pages);
不要直接在路由器扩展中定义路由处理程序,而是将它们加载到对象中,然后执行以下操作:
var Pages = {}
Pages.loginPage = function(){ ... }
Pages.mainPage = function(){ ... }
_.map(Pages,function(func,name){
Pages[name] = _.wrap(func,function(funky){
// Save original arguments
var args = Array.prototype.slice.call(arguments,1);
// Do stuff before the route
funky(args);
// Do stuff after the route
});
});
var myRouter = Backbone.Router.extend({
routes: ... /* as usual */
}).extend(Pages);
如果您需要以不同的方式对待函数的一个子集或其他东西,这也使得检查函数名变得非常容易。然后,因为它只是一个对象,所以可以执行以下操作:
var Pages = {}
Pages.loginPage = function(){ ... }
Pages.mainPage = function(){ ... }
_.map(Pages,function(func,name){
Pages[name] = _.wrap(func,function(funky){
// Save original arguments
var args = Array.prototype.slice.call(arguments,1);
// Do stuff before the route
funky(args);
// Do stuff after the route
});
});
var myRouter = Backbone.Router.extend({
routes: ... /* as usual */
}).extend(Pages);
你完成了
这样做的一个很好的优点是,它不会干扰主干原型,所以即使版本更新改变了一些东西,它也不会影响您 在做了更多的操作之后。我在下面给出了一个解决方案。。。。。。
这里是你的原始根函数
route:function(路由、名称、回调){
如果(!.isRegExp(route))route=this.\u routeToRegExp(route);
if(uu.isFunction(name)){
回调=名称;
名称=“”;
}
如果(!callback)callback=此[名称];
var路由器=这个;
主干。历史。路由(路由,功能(片段){
var args=路由器参数(路由、片段);
callback&&callback.apply(路由器、参数);
router.trigger.apply(路由器,['route:'+name].concat(args));
触发器('route',name,args);
主干.history.trigger('route',router,name,args);
});
归还这个;
}
现在看看这段代码&将“route”函数改为原来的Backbone.js
route: function(route, name, callback) {
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (_.isFunction(name)) {
callback = name;
name = '';
}
if (!callback) callback = this[name];
var router = this;
Backbone.history.route(route, function(fragment) {
// takes matched route & fragment as like 'route1'
var args = router._extractParameters(route, fragment);
// extracts arguments if exists
// here yours self invoking function or other function starts....
(function(){
// do something
if ( true ) // condition satisfies then route to the given Route
{
callback && callback.apply(router, args);
}
else{
name='route2'; // change name of route
window.location.hash = 'route2';
callback= function(){
// optional callback if u want
}
callback && callback.apply(router, args); // route to ur custome Route
}
})();
});
return this;
}
-----多谢各位--------
爱2写肮脏的代码!
@xy….这是一个JavaScript版本,可以使用我所拥有的
var rp = Backbone.Router.prototype;
rp.routeWithoutEvents = rp.route;
rp.route = function(route, name, callback) {
if (!callback) callback = this[name];
this.routeWithoutEvents(route, name, function() {
this.before.apply(this);
callback.apply(this,arguments);
this.after.apply(this);
});
};
它基于Alexey Petrushin和Jonathan Tran的解决方案。这里是一个简单的解决方案,覆盖主干网。路由器本身
(function () {
_.extend(Backbone.Router.prototype, Backbone.Events, {
route: function (route, name, callback) {
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (!callback) callback = this[name];
Backbone.history.route(route, _.bind(function (fragment) {
var args = this._extractParameters(route, fragment);
if (this.before && _.isFunction(this.before)) {
this.before(fragment);
}
callback && callback.apply(this, args);
this.trigger.apply(this, ['route:' + name].concat(args));
if (this.after && _.isFunction(this.after)) {
this.after(fragment);
}
Backbone.history.trigger('route', this, name, args);
}, this));
return this;
}
});
}).call(this);
把重点放在台词上
if (this.before && _.isFunction(this.before)) {
this.before(fragment);
}
及
您可以根据需要修改这些行
这是使用新主干路由器类的客户机代码
var appRouter = Backbone.Router.extend({
routes: {},
before: function(){
//your code here
return true;
}
});
在调用路由处理程序之前,我找不到一种简单的方法来拦截路由事件
我的解决方案是扩展路由器组件,添加一个registerBeforeRouting方法并编辑route方法(我从主干网1.0中获得了它,它工作正常,YMMV具有不同的主干网版本)
在创建路由器之前:
var rp = Backbone.Router.prototype;
rp.registerBeforeRouting = function (callback) {
this._beforeRoutingCallback = callback;
};
rp.route = function (route, name, callback) {
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (_.isFunction(name)) {
callback = name;
name = '';
}
if (!callback) callback = this[name];
var router = this;
Backbone.history.route(route, function(fragment) {
var args = router._extractParameters(route, fragment);
// Edit starts here
// This will trigger the callback previously set
if (typeof router._beforeRoutingCallback === 'function') {
router._beforeRoutingCallback();
}
// Edit stops here.
callback && callback.apply(router, args);
router.trigger.apply(router, ['route:' + name].concat(args));
router.trigger('route', name, args);
Backbone.history.trigger('route', router, name, args);
});
return this;
}
然后,在路由器初始化期间:
this.registerBeforeRouting(function() {
console.log("Hello world");
});
我尝试了前面提到的方法,但不知怎么的,它们对我不起作用(可能是因为我对主干网和javascript都缺乏深入的理解)。
如果有人对我感兴趣的话,我确实设法以其他方式做了这件事:
实际上,我最终做的只是扩展视图并覆盖渲染函数一次
MyApp.BindedView = Backbone.View.extend({
_realRender : null,
initialize : function(){
//validating user is logged in:
if(Backbone.history.fragment != 'login' && !myUser.authenticated())
{
console.log('not authorized, redirecting');
var self = this;
this._realRender = this.render;
this.render = function(route,name,callback){
appRouter.navigate('login');
self.render = self._realRender;
}
return;
}
this.delegateEvents();
}
});
为此目的,添加了要重写的方法。请参见从backbonejs主页提取的示例:
var Router = Backbone.Router.extend({
execute: function(callback, args, name) {
if (!loggedIn) {
goToLogin();
return false;
}
args.push(parseQueryString(args.pop()));
if (callback) callback.apply(this, args);
}
});
这看起来是一个解决方案,但我有一个问题,我看不懂咖啡脚本。有没有办法把它翻译成javascript。我尝试了联机编译器,但这使代码对我来说更不可读。它对我不起作用,但我找到了另一个解决方案。@AmebaSpugnosa指向该解决方案的链接?这对使用“名称”而不是处理程序定义的路由不起作用@AmebaSpugnosa您的解决方案是什么?您的答案更准确,但可能不起作用,因为无法提供回调。在这种情况下,route方法在默认情况下查找名为route name的函数(请参阅我答案中的代码)。@AmebaSpugnosa这一行处理这个问题,所以我不确定您的意思:callback=@[name]if!callback
如果您使用Backbone.js源代码,您将看到Router.route不仅仅准备一个简单的回调。在某些条件下,可以通过命名约定而不是通过引用传递找到回调本身。那个