2013-02-20 2 views
3

У моего приложения есть основной регион, и иногда в основном регионе будут субрегионы, которые должны быть доступны по URL-адресу. Основной контент региона изменяется с помощью функции маршрутизатора приложения, потому что он знает основную область. Но что о временных регионах в подпунктах?Backbone.Marionette Изменить регион при изменении маршрута

Так, например, url /docs отобразит список ссылок на документы, а /doc/:id должен показать содержимое документа рядом со списком. Итак, как может /doc/:id отображать содержимое, когда кто-то нажимает на список и отображает как список, так и контент, когда некоторые открывают URL-адрес на новой вкладке, например.

Насколько я вижу, существует два варианта наличия маршрутизатора для каждого региона, или менеджер региона запускает события с маршрутом и регионом, которые должны измениться. Любые намеки на лучший способ решить эту проблему.

ответ

4

Хорошо, я придумал один маршрутизатор для каждого региона. Маршрутизатор легко настраивается по карте маршрутов и видов. Когда когда-либо маршрут соответствует первому пройденному региону, будет показан новый экземпляр представления.

Here - это расширенная версия маршрутизатора, в которой параметр маршрута передается в представление.

Update

Решение выше работает только до тех пор, каждый маршрут зарегистрирован только один раз. Если вы зарегистрируете один и тот же маршрут во второй раз, то обратный вызов для первого будет переопределен. Поэтому я придумал решение, в котором контроллер региона регистрирует маршрут не непосредственно на маршрутизаторе, но слушает событие route:change на глобальном eventbus (Marionette.Application.vent), а маршрутизатор запускает событие route:change на этой шине событий.

RouterController:

// The problem with backbone router is that it can only register one function per route 
// to overcome this problem every module can register routes on the RouterController 
// the router will just trigger an event on the `app.vent` event bus when ever a registered routes match 
define(function() { 

    function RouterController(vent) { 
    this.vent = vent; 
    this.router = new Backbone.Router(); 
    } 

    RouterController.prototype = _.extend({ 
     //just pass the route that change you wanna listen to 
     addRoutes: function(routes) { 
     _.each(routes, function(route) { 
      this.router.route(
      route, 
      _.uniqueId('e'), 
      //create a closure of vent.trigger, so when ever the route match it simply trigger an event passing the route 
//   _.partial(_.bind(this.vent.trigger, this.vent), 'route:change', route) 
      _.bind(function() { 
       this.vent.trigger.apply(this.vent, ['route:change', route].concat(_.toArray(arguments))); 
      }, this) 
     ); 
     }, this); 

     } 
    }, 
    Backbone.Events); 

    return RouterController; 
}); 

RegionRouter:

define(['common/App'], function(app) { 

    function RegionRouter(region, routerSettings) { 
     app.router.addRoutes(_.keys(routerSettings)); 

     this.listenTo(app.vent, 'route:change', function() { 
     var route = arguments[0]; 
     var View = routerSettings[route]; 

     if (!View) { 
      return; 
     } 

     var params; 

     if (arguments.length > 1) { 
      params = computeParams(arguments, route); 
     } 
     region.show(new View(params)); 
     }); 
    } 

    RegionRouter.prototype = _.extend(
     { 
     onClose: function() { 
      this.stopListening(app.vent); 
     } 
     }, Backbone.Events 
    ); 

    function computeParams(args, route) { 
     args = Array.prototype.slice.call(args, 1); 

     //map the route params to the name in route so /someroute/:somevalue will become {somevalue: passedArgs} 
     //this object will be passed under the parameter key of the options 
     var params = {}; 
     var regEx = /(?::)(\w+)/g; 
     var match = regEx.exec(route); 
     var count = 0; 
     while (match) { 
     params[match[1]] = args[count++]; 
     match = regEx.exec(route); 
     } 

     return {params: params}; 
    } 

    return RegionRouter; 
    } 
);