2011-09-12 48 views

回答

9

_.wrap不是一個解決方案,如果你有例如20條路線,你必須包裝所有。

但是你可以用元編程做這個

class Backbone.FlexRouter extends Backbone.Router 
    route: (route, name, handler) -> 
    super route, name, -> 
     @trigger "route:before" 
     handler() 
     @trigger "route:after" 

UPD:我相信JS就應該是這樣的(但我沒有測試過)

var rp = Backbone.Router.prototype 
rp.routeWithoutEvents = rp.route 
rp.route = function(route, name, handler){ 
    var that = this 
    this.routeWithoutEvents(route, name, function(){ 
    that.trigger("route:before") 
    handler() 
    that.trigger("route:after") 
    }) 
} 
+5

這看起來像一個堅實的解決方案,但我有一個問題,我不能讀取咖啡餡餅。有什麼辦法可以把它轉換成javascript。我已經嘗試過在線編譯器,但是這使得我的代碼更加難以理解。 –

+1

它沒有爲我工作,但我找到了另一種解決方案。 –

+2

@AmebaSpugnosa鏈接到解決方案? – kehers

3

阿列克謝的答案是差不多吧,但也有缺少一些微妙的東西。

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 
+0

你的答案更精確,但它可能無法正常工作,因爲回調可能沒有提供。在這種情況下,路由方法默認查找名爲路由名稱的函數(請參閱我的答案中的代碼)。 –

+0

@AmebaSpugnosa這一行處理,所以我不知道你的意思:'callback = @ [name] if!回調' –

+0

如果您繼續使用Backbone.js源代碼,您將看到Router.route不僅僅準備了一個簡單的回調。在某些情況下,回調本身可以通過命名約定而不是通過引用傳遞來找到。這就是爲什麼你不能像你一樣包裝它。 –

1

我早些時候遇到過這個問題,我想我會分享我的解決方案,將「中間件」插入Backbone路由流。我們的目標是重新路由的用戶,這取決於一些條件不同的流,例如,特徵標誌,會話處理等。

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哈希延長Backbone.ProtectedRouter像這樣:

var router = Backbone.ProtectedRouter.extend({ 
    protectedRoutes: { 
     'home': { 
     assertion: function() { return is_logged_in; }, 
     method: 'renderLogin', 
     args: ['some_arg'] 
     } 
    }, 
    routes: { 
     'home': 'renderHome' 
    }, 
    ... 
}); 

在這種情況下,如果做出請求的home路線和is_logged_infalse,所述renderLogin方法被調用,並通過'some_arg'。流程結束後,renderLogin將返回已解析的延遲,導致原始處理程序(renderHome)被調用。

我希望這會有所幫助。我也非常樂於接受建議! :)

1

我最近碰到這個需求(檢查用戶是否通過驗證)。不幸的是Backbone不會給我們一個事前/事件後的事件,所以你需要覆蓋或擴展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所以this是使用路由器時,你會期望之一。否則,我得到了「這是未定義的」錯誤。

0

ethnagnawl和Alexey都是正確的; _.wrap是正確的解決方案,但是如果你有一堆路線並以正常的骨幹時尚寫入,這將是一個痛苦。我意識到,你可以這樣做:

var Pages = {} 
Pages.loginPage = function(){ ... } 
Pages.mainPage = function(){ ... } 

,而不是直接在Router.extend定義你的路由處理程序,它們加載到一個對象,然後做到這一點:

_.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);  

然後你就完成了。

這樣做的好處之一是它不涉及Backbone原型,所以即使版本更新改變了它也不會咬你。

0

做了很多操作之後。我來,我有如下的解決方案...... 這裏烏爾根原...功能

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); 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; }

現在看這個代碼&改變「路線」功能,原來的骨幹.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 ....

0

這是一個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的解決方案。

6

這裏是簡單的一個,覆蓋Backbone.Router本身

(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); 
} 

if (this.after && _.isFunction(this.after)) { 
    this.after(fragment); 
} 

您可以根據修改的行需要

這裏是使用新Backbone.Router類

var appRouter = Backbone.Router.extend({ 

routes: {}, 
before: function(){ 
    //your code here 
    return true; 
} 

}); 
+1

幹得好。非常感謝你。 – Trip

0

我無法找到一個簡單的方法來攔截路由事件的路由處理程序被調用之前的客戶端代碼。

我的解決方案是擴展路由器組件,添加一個registerBeforeRouting方法並編輯路由方法(我從Backbone 1.0開始使用它,它的工作原理是YMMV和不同的Backbone版本)。

路由器創建前:

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"); 
}); 
0

我嘗試了上述的方法,並在某種程度上只是不爲我工作(可能是我的沒有深入瞭解任何骨幹,也沒有一般的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(); 
    } 
}); 
0

execute的方法被覆蓋用於此目的。看到這個例子從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); 
    } 
}); 
相關問題