Usando o Backbone, é possível obter o nome da rota atual? Eu sei como vincular eventos de alteração de rota, mas gostaria de poder determinar a rota atual em outros momentos, entre as alterações.
Usando o Backbone, é possível obter o nome da rota atual? Eu sei como vincular eventos de alteração de rota, mas gostaria de poder determinar a rota atual em outros momentos, entre as alterações.
Respostas:
Se você instancia um roteador em seu aplicativo, a seguinte linha retornará o fragmento atual:
Backbone.history.getFragment();
Na documentação do Backbone.js :
"[...] O histórico serve como um roteador global (por quadro) para manipular eventos de alteração de hash ou pushState, corresponder à rota apropriada e acionar retornos de chamada. Você nunca precisará criar um desses você mesmo - use a referência para Backbone.history que será criado automaticamente para você se você usar roteadores com rotas. [...] "
Se você precisar do nome da função vinculada a esse fragmento, poderá criar algo assim dentro do escopo do seu roteador:
alert( this.routes[Backbone.history.getFragment()] );
Ou assim de fora do seu roteador:
alert( myRouter.routes[Backbone.history.getFragment()] );
Backbone.history.getFragment()
, porque Backbone.history.fragment
é uma propriedade privada oculta.
A resposta de Robert é interessante, mas infelizmente só funcionará se o hash for exatamente como definido na rota. Se, por exemplo, você tiver uma rota, user(/:uid)
ela não corresponderá se Backbone.history.fragment
é "user"
ou "user/1"
(ambos os dois casos de uso mais óbvios para essa rota). Em outras palavras, ele encontrará apenas o nome de retorno de chamada apropriado se o hash for exatamente"user(/:uid)"
(altamente improvável).
Como eu precisava dessa funcionalidade, estendi a função Backbone.Router
with current
que reutiliza parte do código que o objeto History and Router usa para corresponder o fragmento atual às rotas definidas para acionar o retorno de chamada apropriado. Para o meu caso de uso, é necessário o parâmetro opcional route
, que, se definido como algo verdadeiro, retornará o nome da função correspondente definido para a rota. Caso contrário, ele retornará o atual fragmento de hash deBackbone.History.fragment
.
Você pode adicionar o código ao seu Extend existente, onde inicializa e configura o roteador Backbone.
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'
Tenho certeza de que algumas melhorias podem ser feitas, mas essa é uma boa maneira de começar. Além disso, é fácil criar essa funcionalidade sem estender o objeto Route. Fiz isso porque era a maneira mais conveniente para a minha configuração.
Ainda não testei isso completamente, por favor, avise-me se algo der para o sul.
Fiz algumas alterações na função. Portanto, em vez de retornar o nome de retorno de chamada de hash ou rota, retorno um objeto com fragmentos, parâmetros e rota para que você possa acessar todos os dados da rota atual, como faria com a rota- evento.
Você pode ver as alterações abaixo:
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
};
}
Veja o código anterior para mais comentários e explicações, eles têm a mesma aparência.
_.find
função como this
, eliminando assim a necessidade da Router
variável (o @DanAbramov já fez isso).
Marionette.AppRouter
, estenda seu roteador com a função acima, mas substitua Router.appRoutes
-o Router.routes
.
Para obter a rota (ou URL) de chamada do manipulador de rota chamado, você pode obtê-la verificando
Backbone.history.location.href ... o URL completo Backbone.history.location.search ... sequência de consultas a partir de?
Cheguei aqui na busca desta resposta, então acho que devo deixar o que encontrei.
Se você usar a configuração raiz do roteador, também poderá incluí-la para obter o fragmento 'real'.
(Backbone.history.options.root || "") + "/" + Backbone.history.fragment
Aqui está uma versão um pouco mais detalhada (ou, dependendo do seu gosto, mais legível) da resposta de Simon :
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
};
}
}
Se você procurar na fonte Router
, verá que, quando o roteador aciona o evento dizendo que algo muda, ele passa o nome como "route: name".
http://documentcloud.github.com/backbone/docs/backbone.html#section-84
Você sempre pode conectar o evento "route" ao roteador e armazená-lo para obter a rota atual.
route
evento se trigger
não for true
(recomendado e padrão).