несколько совпадающих маршрутов - PullRequest
12 голосов
/ 07 марта 2011

У меня есть приложение backbone.js, которое определяет два контроллера, и оба контроллера определяют шаблоны маршрутов, которые соответствуют location.hash. У меня проблемы с тем, чтобы заставить их обоих стрелять - например,

ManagerController = Backbone.Controller.extend({
   routes: {
      ":name":      "doStuff"
   },

   doStuff : function(name) {
      console.log("doStuff called...");
   }
});

Component1Controller = Backbone.Controller.extend({
   routes: {
      "xyz123":      "doMoreStuff"
   },

   doMoreStuff : function() {
      console.log("doMoreStuff called...");
   }
});

поэтому, если URL-адрес "http://mysite.com/#xyz123",", я вижу, что вызывается функция doStuff (), или если я закомментирую этот маршрут, то вызывается функция "doMoreStuff ()".

Я использую эту архитектуру, потому что моя страница сильно ориентирована на компоненты, и каждый компонент определяет свой собственный контроллер. «Диспетчер компонентов» также определяет контроллер, который ведет домашнюю работу на всех маршрутах.

Могу ли я настроить два контроллера, которые отвечают на один и тот же маршрут? Cheers,

Colin

Ответы [ 5 ]

15 голосов
/ 08 марта 2011

Краткий ответ: Нет, вы не можете этого сделать.Один контроллер на страницу.

Длинный ответ: Когда вы создаете экземпляр нового контроллера, он добавляет свои маршруты в одноэлементную историю.Синглтон History отслеживает хеш-компонент URL-адреса и, когда хеш-код изменяется, сканирует маршруты для выражения first , которое соответствует его потребностям.Затем он запускает функцию, связанную с этим маршрутом (эта функция была связана с контроллером, в котором она была объявлена).Он будет срабатывать только один раз, и в случае конфликта порядок его запуска формально не определен.(На практике это, вероятно, является детерминированным.)

Философский ответ: Контроллер - это объект «просмотра», который влияет на представление всей страницы на основе хеш-компонента URL.Его целью является предоставление URL-адресов с возможностью закладок, которые пользователь сможет получить в будущем, чтобы при переходе по URL-адресу он мог начать с предварительно выбранного представления среди многих.Из вашего описания звучит так, будто вы манипулируете этим публично доступным, адресуемым вручную элементом, чтобы манипулировать различными частями вашего окна просмотра, оставляя других в покое.Это не так.

Одна из приятных особенностей Backbone заключается в том, что если вы передадите ему маршрут, который уже является регулярным выражением, он будет использовать его как есть.Поэтому, если вы пытаетесь использовать контроллер для создания закладочного описания макета (компонент 1 в верхнем правом углу в режиме отображения «A», компонент 2 в верхнем левом углу в режиме отображения «B» и т. Д.)Я могу предложить несколько альтернатив - выделить каждому из них пространство имен в хэш-части URL-адреса и создать маршруты, которые игнорируют остальные, т. Е.

routes: {
    new RegExp('^([^\/]*)/.*$'): 'doComponent1stuff',
    new RegExp('^[^\/]*/([^\/]*)\/.*$': 'doComponent2stuff',
}

Посмотрите, как первый использует только элементы после первогокосая черта, вторая после второй косой черты и т. д. Вы можете полностью закодировать свою магию так, как хотите.

Я предлагаю, однако, что если вы собираетесь что-то делать с внешним видом и ощущением компонентови вы хотите, чтобы это было достаточно настойчиво, чтобы вы просматривали представления, получая и устанавливая их куки-файлы из какого-то локального магазина;если они достаточно маленькие, куки будет достаточно.

7 голосов
/ 13 мая 2011

У меня очень похожая проблема. В настоящее время магистраль останавливается после первого соответствующего маршрута. У меня есть грязный обходной путь, где я переопределяю метод loadUrl Backbone History. Здесь я перебираю все зарегистрированные маршруты и запускаю обратный вызов для всех соответствующих маршрутов.

_.extend(Backbone.History.prototype, {
  loadUrl : function() {
    var fragment = this.fragment = this.getFragment();
    var matched = false;
    _.each(this.handlers, function(handler) {
      if (handler.route.test(fragment)) {
        handler.callback(fragment);
        matched = true;
      }
    });
    return matched;
  }
})

С точки зрения философии, у меня все в порядке с одним контроллером на страницу. Однако в компонентной структуре представления было бы неплохо иметь несколько представлений на маршрут, визуализирующих различные части состояния представления.

Комментарии приветствуются.

1 голос
/ 25 июня 2011

Я использовал пространство имен для решения аналогичной проблемы. Каждый модуль поставляется со своим собственным контроллером модуля, но он ограничен для обработки маршрутов, начинающихся с / moduleName /, таким образом модули могут разрабатываться независимо.

0 голосов
/ 15 марта 2016

Я думаю, что это самый простой способ решения проблемы

0 голосов
/ 12 декабря 2013

Я еще не полностью проверил это, если вы посмотрите на источник Backbone.js, вы можете увидеть это в строке 1449:

// Attempt to load the current URL fragment. If a route succeeds with a
// match, returns `true`. If no defined routes matches the fragment,
// returns `false`.
loadUrl: function(fragment) {
  fragment = this.fragment = this.getFragment(fragment);
  return _.any(this.handlers, function(handler) {
    if (handler.route.test(fragment)) {
      handler.callback(fragment);
      return true;
    }
  });
}

Любой метод остановится, как только он совпадет с маршрутом обработчика (с «return true»), просто прокомментируйте возврат, и короткое замыкание никогда не произойдет, и все обработчики будут протестированы. Протестировал это с помощью приложения марионеток с двумя модулями, каждый из которых имеет собственный маршрутизатор и контроллер, прослушивая одинаковые маршруты и оба запускаются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...