2011-09-12 40 views

Trả lời

9

_.wrap không phải là giải pháp, nếu bạn có ví dụ 20 tuyến đường bạn phải gói tất cả.

Nhưng bạn có thể làm điều này với lập trình meta

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

UPD: Tôi tin vào JS nó phải được một cái gì đó như thế này (nhưng tôi đã không kiểm tra nó)

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

Điều này trông giống như một giải pháp vững chắc, nhưng tôi có một vấn đề, tôi không thể đọc coffeesript. Có cách nào bạn có thể dịch này vào javascript. Tôi đã thử trình biên dịch trực tuyến, nhưng điều đó làm cho mã thậm chí còn khó đọc hơn đối với tôi. –

+1

Nó không hiệu quả với tôi, nhưng tôi đã tìm ra một giải pháp khác. –

+2

@AmebaSpugnosa Liên kết với giải pháp? – kehers

3

Alexey của câu trả lời là gần như ngay, nhưng có một vài điều tế nhị mà đang thiếu.

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

Câu trả lời của bạn chính xác hơn, nhưng nó có thể không hoạt động vì không thể cung cấp tính năng gọi lại. Trong trường hợp đó, phương thức route theo mặc định sẽ tìm một hàm có tên là tên route (xem mã trong câu trả lời của tôi). –

+0

@AmebaSpugnosa dòng này xử lý, vì vậy tôi không chắc chắn những gì bạn có nghĩa là: 'callback = @ [name] if! callback' –

+0

Nếu bạn đi trên mã nguồn Backbone.js, bạn sẽ thấy rằng Router.route không chỉ chuẩn bị một cuộc gọi đơn giản. Các cuộc gọi lại chính nó, trong điều kiện nhất định, có thể được tìm thấy bằng cách đặt tên quy ước và không phải bằng cách tham khảo đi qua. Đó là lý do tại sao bạn không thể chỉ quấn nó như bạn đã làm. –

1

Tôi đã gặp vấn đề này trước đó và tôi nghĩ mình sẽ chia sẻ giải pháp của mình để chèn "phần mềm trung gian" vào luồng định tuyến Backbone. Mục đích là để định tuyến lại người dùng các dòng khác nhau tùy thuộc vào một số điều kiện, ví dụ như, cờ tính năng, xử lý phiên làm việc, vv ..

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

Từ đó bạn có thể dễ dàng mở rộng Backbone.ProtectedRouter với một hash protectedRoutes như vậy:

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

Trong tình huống này, nếu yêu cầu được thực hiện cho con đường homeis_logged_infalse, phương pháp renderLogin được gọi và thông qua 'some_arg'. Sau khi luồng, renderLogin sẽ trả về Trì hoãn đã giải quyết khiến trình xử lý ban đầu (renderHome) được gọi.

Tôi hy vọng điều này sẽ hữu ích. Tôi cũng rất cởi mở với các đề xuất! :)

1

Tôi đã xem xét nhu cầu này gần đây (để kiểm tra người dùng được xác thực). Thật không may Backbone không cung cấp cho chúng ta một sự kiện trước/sau, vì vậy bạn sẽ cần phải ghi đè hoặc mở rộng Router.route. Không cảm thấy rất sạch sẽ vì bạn phải sao chép từ mã nguồn và chỉnh sửa ở đó, nhưng là cách duy nhất tôi tìm thấy. Dưới đây đang Backbone mặc định (1.0.0) và đánh dấu mã tùy chỉnh của tôi:

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

Thông báo _.wrap_.bind nên this là một mà bạn mong đợi khi sử dụng router. Nếu không, tôi đã nhận được một lỗi "này là không xác định".

0

ethnagnawl và Alexey đều chính xác; _.wrap là giải pháp phù hợp nhưng nếu bạn có một loạt các tuyến đường và viết chúng theo kiểu xương sống bình thường thì nó sẽ là một cơn đau.Tôi nhận ra bạn có thể làm điều này:

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

Thay vì xác định xử lý tuyến đường của bạn trực tiếp trong Router.extend, tải chúng vào một đối tượng và sau đó làm điều này:

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

này cũng làm cho nó khá dễ dàng để kiểm tra tên hàm nếu bạn cần xử lý một tập hợp con của chúng một cách khác nhau hoặc một cái gì đó. Sau đó, bởi vì nó chỉ là một đối tượng, bạn có thể làm điều này:

var myRouter = Backbone.Router.extend({ 
    routes: ... /* as usual */ 
    }).extend(Pages);  

Và bạn đã hoàn tất.

Một lợi thế tốt đẹp của việc này là nó không liên quan đến các nguyên mẫu Backbone, vì vậy ngay cả khi cập nhật phiên bản thay đổi một cái gì đó nó sẽ không cắn bạn.

0

sau khi thực hiện nhiều thao tác hơn. i đến một giải pháp mà tôi đã đưa ra dưới đây ...... Đây ur chức năng gốc ban đầu ...

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

Bây giờ nhìn vào mã này & thay đổi "lộ trình" chức năng để Backbone ban đầu của bạn .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; 
} 

----- Cảm ơn bạn -------- Love 2 write Dirty Codes! @xy ....

0

Đây là phiên bản JavaScript hoạt động với những gì tôi có;

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

Nó dựa trên các giải pháp của Alexey Petrushin và Jonathan Tran.

6

Đây là một trong những đơn giản, trọng các Backbone.Router tự

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

Tập trung vào các dòng

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

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

Bạn có thể sửa đổi các dòng theo của bạn cần

Và đây là mã khách hàng sử dụng các lớp Backbone.Router mới

var appRouter = Backbone.Router.extend({ 

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

}); 
+1

Thực hiện tốt. Cảm ơn nhiều. – Trip

0

tôi không thể tìm thấy một cách dễ dàng để đánh chặn các sự kiện định tuyến trước khi xử lý tuyến đường được gọi.

Giải pháp của tôi là mở rộng thành phần Bộ định tuyến, thêm phương thức registerBeforeRouting và chỉnh sửa phương thức tuyến đường (tôi lấy nó từ Backbone 1.0 và nó hoạt động, YMMV với các phiên bản Backbone khác nhau).

Trước khi router được tạo ra:

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

Sau đó, trong bộ định tuyến khởi tạo:

this.registerBeforeRouting(function() { 
    console.log("Hello world"); 
}); 
0

Tôi đã thử các cách tiếp cận nói trên, và họ bằng cách nào đó chỉ không làm việc cho tôi (có lẽ cho tôi thiếu hiểu biết sâu sắc về cả xương sống lẫn javascript nói chung). Tôi đã cố gắng thực hiện thủ thuật theo cách khác, nếu bất kỳ ai quan tâm đến bất kỳ ai:

Điều tôi thực sự làm chỉ đơn giản là kéo dài Chế độ xem và ghi đè hàm kết xuất chỉ một lần.

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

Phương pháp execute đã được thêm vào để ghi đè cho mục đích này. Xem ví dụ này được trích xuất từ ​​trang chủ 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); 
    } 
}); 
Các vấn đề liên quan