Несколько маршрутов соответствия
У меня есть приложение 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,
Колин
Ответы
Ответ 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',
}