Могу ли я получить имя текущего маршрута, используя Backbone? Я знаю, как выполнить привязку к событиям изменения маршрута, но я хотел бы иметь возможность определять текущий маршрут в другое время, между изменениями.
Могу ли я получить имя текущего маршрута, используя Backbone? Я знаю, как выполнить привязку к событиям изменения маршрута, но я хотел бы иметь возможность определять текущий маршрут в другое время, между изменениями.
Ответы:
Если вы создали экземпляр Router в своем приложении, следующая строка возвращает текущий фрагмент:
Backbone.history.getFragment();
"[...] История служит глобальным маршрутизатором (для каждого кадра) для обработки событий hashchange или pushState, сопоставления с соответствующим маршрутом и запуска обратных вызовов. Вам никогда не придется создавать один из них самостоятельно - вы должны использовать ссылку в Backbone.history, который будет создан автоматически, если вы используете маршрутизаторы с маршрутами. [...] "
Если вам нужно имя функции, связанной с этим фрагментом, вы можете сделать что-то вроде этого внутри области видимости вашего маршрутизатора:
alert( this.routes[Backbone.history.getFragment()] );
Или вот так извне вашего роутера:
alert( myRouter.routes[Backbone.history.getFragment()] );
Backbone.history.getFragment()
, потому что Backbone.history.fragment
это частная скрытая собственность.
Ответ Роберта интересен, но, к сожалению, он будет работать только в том случае, если хеш будет точно таким, как определено в маршруте. Например, если у вас есть маршрут для user(/:uid)
него, он не будет сопоставлен, если Backbone.history.fragment
будет либо, "user"
либо "user/1"
(оба являются двумя наиболее очевидными вариантами использования для такого маршрута). Другими словами, он найдет подходящее имя обратного вызова только в том случае, если хэш точный "user(/:uid)"
(очень маловероятно).
Поскольку мне нужна была эта функциональность, я расширил ее Backbone.Router
с помощью current
-функции, которая повторно использует часть кода, используемого объектом History и Router, для сопоставления текущего фрагмента с определенными маршрутами для запуска соответствующего обратного вызова. Для моего варианта использования он принимает необязательный параметр route
, который, если задано что-либо правдивое, вернет соответствующее имя функции, определенное для маршрута. В противном случае он вернет текущий хеш-фрагмент из Backbone.History.fragment
.
Вы можете добавить код в существующий Extend, где вы инициализируете и настраиваете Backbone router.
var Router = new Backbone.Router.extend({
// Pretty basic stuff
routes : {
"home" : "home",
"user(:/uid)" : "user",
"test" : "completelyDifferent"
},
home : function() {
// Home route
},
user : function(uid) {
// User route
},
// Gets the current route callback function name
// or current hash fragment
current : function(route){
if(route && Backbone.History.started) {
var Router = this,
// Get current fragment from Backbone.History
fragment = Backbone.history.fragment,
// Get current object of routes and convert to array-pairs
routes = _.pairs(Router.routes);
// Loop through array pairs and return
// array on first truthful match.
var matched = _.find(routes, function(handler) {
var route = handler[0];
// Convert the route to RegExp using the
// Backbone Router's internal convert
// function (if it already isn't a RegExp)
route = _.isRegExp(route) ? route : Router._routeToRegExp(route);
// Test the regexp against the current fragment
return route.test(fragment);
});
// Returns callback name or false if
// no matches are found
return matched ? matched[1] : false;
} else {
// Just return current hash fragment in History
return Backbone.history.fragment
}
}
});
// Example uses:
// Location: /home
// console.log(Router.current()) // Outputs 'home'
// Location: /user/1
// console.log(Router.current(true)) // Outputs 'user'
// Location: /user/2
// console.log(Router.current()) // Outputs 'user/2'
// Location: /test
// console.log(Router.current(true)) // Outputs 'completelyDifferent'
Я уверен, что можно было бы кое-что улучшить, но это хороший способ начать работу. Кроме того, эту функциональность легко создать без расширения объекта Route. Я сделал это, потому что это был наиболее удобный способ для моей настройки.
Я еще не тестировал это полностью, поэтому, пожалуйста, дайте мне знать, если что-то пойдет не так.
Я внес некоторые изменения в функцию, поэтому вместо того, чтобы возвращать хэш или имя обратного вызова маршрута, я возвращаю объект с фрагментом, параметрами и маршрутом, чтобы вы могли получить доступ ко всем данным из текущего маршрута, так же, как вы бы из маршрута- событие.
Вы можете увидеть изменения ниже:
current : function() {
var Router = this,
fragment = Backbone.history.fragment,
routes = _.pairs(Router.routes),
route = null, params = null, matched;
matched = _.find(routes, function(handler) {
route = _.isRegExp(handler[0]) ? handler[0] : Router._routeToRegExp(handler[0]);
return route.test(fragment);
});
if(matched) {
// NEW: Extracts the params using the internal
// function _extractParameters
params = Router._extractParameters(route, fragment);
route = matched[1];
}
return {
route : route,
fragment : fragment,
params : params
};
}
См. Предыдущий код для дальнейших комментариев и объяснений, они в основном выглядят одинаково.
_.find
функции как this
, тем самым устраняя необходимость в Router
переменной (@DanAbramov уже сделал это).
Marionette.AppRouter
, расширить маршрутизатор с функцией выше, но замена Router.appRoutes
для Router.routes
.
Чтобы получить маршрут вызова (или URL-адрес) от вызываемого обработчика маршрута, вы можете получить его, проверив
Backbone.history.location.href ... полный URL Backbone.history.location.search ... строка запроса, начиная с?
Я попал сюда в поисках этого ответа, поэтому, думаю, мне следует оставить то, что я нашел.
Если вы используете корневую настройку для маршрутизатора, вы также можете включить ее, чтобы получить «настоящий» фрагмент.
(Backbone.history.options.root || "") + "/" + Backbone.history.fragment
Вот чуть более многословным (или, в зависимости от вашего вкуса, более удобным для чтения) версии ответа Саймона :
current: function () {
var fragment = Backbone.history.fragment,
routes = _.pairs(this.routes),
route,
name,
found;
found = _.find(routes, function (namedRoute) {
route = namedRoute[0];
name = namedRoute[1];
if (!_.isRegExp(route)) {
route = this._routeToRegExp(route);
}
return route.test(fragment);
}, this);
if (found) {
return {
name: name,
params: this._extractParameters(route, fragment),
fragment: fragment
};
}
}
Если вы посмотрите на источник Router
, вы увидите, что когда маршрутизатор запускает событие, говоря, что что-то меняется, он передает имя с ним как «route: name».
http://documentcloud.github.com/backbone/docs/backbone.html#section-84
Вы всегда можете подключить событие "route" к маршрутизатору и сохранить его, чтобы получить текущий маршрут.
route
событие, если trigger
его не будет true
(рекомендуется и по умолчанию).
router = new Backbone.Router.extend({
routes: { "stuff/:id" : "stuff" },
stuff: function(id) {}
});
router.on('route', function(route) {
this.current = route;
});
Теперь, если вы /stuff/1
перейдете к , router.current будет "stuff"