Backbone.js: obtener la ruta actual


137

Con Backbone, ¿puedo obtener el nombre de la ruta actual? Sé cómo vincularme con los eventos de cambio de ruta, pero me gustaría poder determinar la ruta actual en otros momentos, entre cambios.


Por "nombre", ¿quiere decir la función a la que se vincula esa ruta o cuál es la URL actual o la porción hash de la URL?
John Munsch

1
Oh, sí, debería haber sido más específico. Me gustaría saber el nombre de la función. (Sé cómo obtener la porción hash de la URL haciendo location.hash o Backbone.history.fragment.)
Drew Dara-Abrams

Respuestas:


209

Si ha instanciado un enrutador en su aplicación, la siguiente línea devuelve el fragmento actual:

Backbone.history.getFragment();

De la documentación de Backbone.js :

"El [...] historial sirve como un enrutador global (por trama) para manejar eventos de cambio de hash o pushState, hacer coincidir la ruta apropiada y activar devoluciones de llamada. Nunca debería tener que crear uno de estos, debe usar la referencia a Backbone.history que se creará para usted automáticamente si utiliza enrutadores con rutas. [...] "

Si necesita el nombre de la función vinculada a ese fragmento, puede hacer algo como esto dentro del alcance de su enrutador:

alert( this.routes[Backbone.history.getFragment()] );

O así desde fuera de su enrutador:

alert( myRouter.routes[Backbone.history.getFragment()] );

Gracias, eso es genial. Nunca me pareció ninguna mención de Backbone.history.fragment en el documento. ¿Es esta una nueva adición, o simplemente indocumentada?
Drew Dara-Abrams

Creo que esto no está documentado. En realidad, no recuerdo dónde lo vi por primera vez, algún blog o quizás el código fuente de la red troncal.
Robert

25
FYI, esto no funciona con rutas como 'foo /: id' o 'bar * params'
wprl

2
Mejor uso Backbone.history.getFragment(), porque Backbone.history.fragmentes una propiedad privada oculta.
Vad

1
He corregido la respuesta siguiendo la sugerencia de @Vad. Ya no uso Backbone, pero su comentario me parece correcto. (La respuesta anterior fue: Backbone.history.fragment en lugar de Backbone.history.getFragment ())
Robert

57

La respuesta de Robert es interesante, pero lamentablemente solo funcionará si el hash es exactamente como se define en la ruta. Si, por ejemplo, tiene una ruta user(/:uid), no coincidirá si Backbone.history.fragmentes uno "user"o "user/1"ambos (ambos son los dos casos de uso más obvios para dicha ruta). En otras palabras, solo encontrará el nombre de devolución de llamada apropiado si el hash es exactamente "user(/:uid)"(muy poco probable).

Como necesitaba esta funcionalidad, extendí la función Backbone.Routercon una currentfunción que reutiliza parte del código que usan los objetos Historial y Enrutador para hacer coincidir el fragmento actual con las Rutas definidas para activar la devolución de llamada apropiada. Para mi caso de uso, toma el parámetro opcional route, que si se establece en algo verdadero devolverá el nombre de la función correspondiente definida para la ruta. De lo contrario, devolverá el fragmento hash actual de Backbone.History.fragment.

Puede agregar el código a su extensión existente donde inicializa y configura el enrutador 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'

Estoy seguro de que se podrían hacer algunas mejoras, pero esta es una buena manera de comenzar. Además, es fácil crear esta funcionalidad sin extender el objeto Ruta. Hice esto porque era la forma más conveniente para mi configuración.

Todavía no lo he probado completamente, así que avíseme si algo va mal.


ACTUALIZACIÓN 25/04/2013

Hice algunos cambios en la función, por lo que en lugar de devolver el nombre de devolución de llamada hash o ruta, devuelvo un objeto con fragmento, parámetros y ruta para que pueda acceder a todos los datos de la ruta actual, al igual que lo haría desde la ruta. evento.

Puedes ver los cambios a continuación:

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
    };
}

Vea el código anterior para más comentarios y explicaciones, se ven casi iguales.


1
Estaba a punto de escribir esto yo mismo, pero busqué en Google la solución primero. Me alegro de haberlo hecho. El tuyo hace exactamente lo que quería, ¡gracias!
Dan Abramov

Aquí hay una versión un poco más detallada que creo que es más fácil de entender a primera vista.
Dan Abramov

44
Wow, gracias por esto! Acabas de recibir un reconocimiento en nuestra base de código. ; P Lo modificamos ligeramente para Marionette. Por cierto, como acceso directo, puede establecer el tercer parámetro (establece el contexto) de la _.findfunción como this, eliminando así la necesidad de la Routervariable (@DanAbramov ya lo hizo).
Marcar

@ Mark Estas son buenas noticias. Pero, ¿cómo puedo usar esta función en marionetas? No hay nada al respecto en los documentos.
darksoulsong

2
@darksoulsong Si estás usando Marionette.AppRouter, ampliar su router con la función anterior, pero sustituto Router.appRoutespara Router.routes.
Mark

11

Para obtener la ruta de llamada (o url) del controlador de ruta llamado, puede obtenerla marcando

Backbone.history.location.href ... la url completa
Backbone.history.location.search ... cadena de consulta a partir de?

Llegué aquí en busca de esta respuesta, así que supongo que debería dejar lo que he encontrado.


6

Si usa la configuración raíz para el enrutador, también puede incluirla para obtener el fragmento 'real'.

(Backbone.history.options.root || "") + "/" + Backbone.history.fragment

6

Aquí hay una versión un poco más detallada (o, según su gusto, más legible) de la respuesta 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
    };
  }
}

4

Si observa el origen del Router, verá que cuando el enrutador activa el evento diciendo que algo cambia, pasa el nombre con él como "ruta: nombre".

http://documentcloud.github.com/backbone/docs/backbone.html#section-84

Siempre puede conectar el evento "ruta" en el enrutador y almacenarlo para obtener la ruta actual.


De acuerdo, supongo que esto es un tipo de "construido por ti mismo".
Drew Dara-Abrams

Sí, pero no obtendrá el routeevento si trigger no lo está true (recomendado y predeterminado).
Dan Abramov
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.