Подтвердить что ты не робот

Несколько маршрутов соответствия

У меня есть приложение 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,

Колин

4b9b3361

Ответ 1

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

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

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

Одна из приятных вещей в Backbone заключается в том, что если вы передадите ей маршрут, который уже является регулярным выражением, он будет использовать его как есть. Поэтому, если вы пытаетесь использовать контроллер для создания закладок описания макета (компонент 1 в верхнем правом углу в режиме отображения "А", компонент 2 в верхнем левом углу в режиме отображения "В" и т.д.), Я могу предложить несколько альтернатив: выделите каждое пространство имен в хэш-части URL-адреса и создайте маршруты, которые игнорируют остальные, т.е.

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

Я еще не полностью протестировал это, если вы посмотрите на источник 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;
    }
  });
}

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

Ответ 5

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

маршруты: { '': 'userGrid', 'users': 'userGrid', }