Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Backbone.js—;在触发路由之前/之后调用方法_Backbone.js_Routes_Router - Fatal编程技术网

Backbone.js—;在触发路由之前/之后调用方法

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

我希望在我的Backbone.js路由器中触发路由之前和之后分别调用setup/teardown方法。有没有人创造了一种优雅的方式

您考虑过吗?

包裹不是一个解决方案,例如,如果您有20条路线,您必须将它们全部包裹起来

但是你可以用元编程来实现这一点

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不仅仅准备一个简单的回调。在某些条件下,可以通过命名约定而不是通过引用传递找到回调本身。那个