Backbone.js:获取当前路线


137

使用Backbone,我能否获得当前路线的名称?我知道如何绑定到路线更改事件,但是我希望能够在其他时间确定更改之间的当前路线。


“名称”是指该路由绑定到的功能还是当前URL或URL的哈希部分是什么?
约翰·蒙施

1
哦,是的,我应该更具体一些。我想知道函数的名称。(我知道如何通过location.hash或Backbone.history.fragment获取URL的哈希部分。)
Drew Dara-Abrams

Answers:


209

如果您已在应用程序中实例化了路由器,则以下行将返回当前片段:

Backbone.history.getFragment();

Backbone.js文档中

“ [...]历史记录充当全局路由器(每帧),以处理hashchange事件或pushState,匹配适当的路由并触发回调。您不必自己创建其中的一个- 您应该使用引用到Backbone.history,如果您使用带有路由的路由器,则会自动为您创建。[...]“

如果需要绑定到该片段的函数的名称,则可以在Router范围内进行如下操作:

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

或从路由器外部这样:

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

谢谢,太好了。我似乎从未在文档中提及Backbone.history.fragment。这是一个新的补充,还是只是没有记载?
德鲁·达拉·阿布拉姆斯

我认为这是无证的。实际上,我不记得我在哪里第一次看到它,有些博客甚至是骨干源代码。
罗伯特

25
仅供参考,这不适用于'foo /:id'或'bar * params'之类的路由
wprl 2013年

2
最好使用Backbone.history.getFragment(),因为Backbone.history.fragment它是私有的隐藏属性。
Vad 2015年

1
我已按照@Vad建议更正了答案。我不再使用Backbone,但他的评论对我来说很正确。(先前的答案是:Backbone.history.fragment而不是Backbone.history.getFragment())
罗伯特·罗伯特

57

罗伯特的答案很有趣,但可悲的是,只有在哈希值完全符合路由定义的情况下,它才有效。例如,如果您有一条路线,user(/:uid)则如果Backbone.history.fragment"user"或则不匹配"user/1"(两者都是该路线的两个最明显的用例)。换句话说,只有在哈希完全正确"user(/:uid)"(极不可能)的情况下,它才会找到适当的回调名称。

由于我需要此功能,因此我Backbone.Router使用current- 函数扩展了-功能,该功能可复用一些历史和路由器对象用来将当前片段与定义的Routes相匹配的代码,以触发适当的回调。在我的用例中,它采用了可选参数route,如果将其设置为true,则将返回为路由定义的相应函数名称。否则,它将从返回当前的哈希片段Backbone.History.fragment

您可以将代码添加到现有的Extend中,以在其中初始化和设置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'

我确定可以进行一些改进,但这是一个入门的好方法。同样,无需扩展Route对象即可轻松创建此功能。我这样做是因为这是我设置的最方便的方法。

我尚未对此进行全面测试,所以请让我知道是否有任何问题。


更新04/25/2013

我对该函数进行了一些更改,因此我返回了一个带有片段,参数和路由的对象,而不是返回哈希或路由回调名称,因此您可以访问当前路由中的所有数据,就像从路由中那样:事件。

您可以看到以下更改:

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

请参阅前面的代码以获取更多注释和解释,它们看起来大致相同。


1
本来要自己写的,但首先搜索Google解决方案。很高兴我做到了。您的工作正是我想要的,谢谢!
Dan Abramov

这是一个稍微冗长的版本,我相信乍一看会更容易理解。
Dan Abramov

4
哇,谢谢你!您刚刚在我们的代码库中得到了认可。; P我们对木偶进行了微调。顺便说一句,作为快捷方式,您可以将函数的第三个参数(设置上下文)设置_.findthis,从而消除了对Router变量的需要(@DanAbramov已经做到了)。
标记

@Mark这些都是好消息。但是,如何在木偶中使用此功能?在文档中没有关于它的任何内容。
darksoulsong 2014年

2
@darksoulsong如果您使用Marionette.AppRouter,上面的功能,但替补延长你的路由器Router.appRoutesRouter.routes
2014年

11

要从被调用的路由处理程序获取调用路由(或网址),可以通过检查

Backbone.history.location.href ...完整网址
Backbone.history.location.search ...查询字符串从?开始

我到达这里是为了寻找答案,所以我想我应该离开找到的内容。


6

如果您为路由器使用根设置,则还可以包括它以获得“真实”片段。

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

6

这里有一个稍微更详细的(或者,取决于你的口味,更易读)的版本西蒙的回答

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

如果您查看的来源Router,您会看到当路由器触发事件​​说发生了某些变化时,它将通过名称传递它为“ route:name”。

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

您始终可以在路由器上挂接“ route”事件,并将其存储以获取当前路由。


好的,我想这是“自己构建”的事情。
德鲁·达拉·阿布拉姆斯

是的,但你不会得到route,如果事件trigger 没有 true(建议与默认)。
Dan Abramov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.