【问题标题】:Is there a way to catch all non-matched routes with Backbone?有没有办法用 Backbone 捕获所有不匹配的路由?
【发布时间】:2012-06-27 23:51:55
【问题描述】:

我希望有一个“catch all”路由,该路由在没有其他定义的路由匹配时运行。一种 404 NotFound 错误处理程序。

我试过添加这个,它可以工作,但会阻止其他路由匹配:

this.route(/(.*)/, 'notFound', this.notFound);

以前有人解决过这个问题吗?

【问题讨论】:

    标签: javascript backbone.js router


    【解决方案1】:

    为了完整起见,在此回答。

    您可以通过两种方式做到这一点。如问题所示,使用route() 定义正则表达式。但是,由于this bug,您需要通过route() 方法以相反的顺序定义所有路由(顶部的总括)。这会阻止您使用路由哈希,因此(我的)首选方法是:

    routes: {
      'users/search': 'searchUsers',
      'users/:id': 'loadUser',
    
      '*notFound': 'notFound'
    }
    

    密钥'*notFound' 实际上可以是任何以* 开头的东西。您只需要 * 之后的字符来防止解析错误。

    【讨论】:

    • 这个路由问题是 Backbone 和 they're still doing it 中的一个重大失误,JavaScript 规范没有说明 object keys enumerating in source order 或任何其他特定顺序,除了它在各个地方都是相同的。取决于routes,以任何特定顺序枚举只是要求它。唯一确定的方法是手动使用route()
    • 我不知道我以前怎么没有发现这个,你真是天赐良机!
    • 如果您需要正则表达式并使用this.route,您有什么想法吗?我认为@machineghost 下面的答案可能是一个更好的解决方案。 backbonejs.org/#History-start
    • 如果你有多个路由器呢?订购是如何运作的?
    • @muistooshort Yeoman 做同样的事情。在实践中,我认为依赖对象键顺序可能是可以的。由于依赖顺序已经成为一种广泛的做法,我认为浏览器/javascript 实现永远不会不符合。
    【解决方案2】:

    还有另一种可以说更简单/更优雅的方法来解决这个问题。 Backbone.History.start() 根据是否匹配路由返回 true 或 false。所以,如果你这样做:

    if (!Backbone.history.start()) router.navigate('404', {trigger:true});
    

    而不是通常的:

    Backbone.History.start();
    

    它将与其他答案具有相同的效果。

    【讨论】:

    • 这是怎么被埋没的? router.trigger 位已过时,但逻辑合理! backbonejs.org/#History-start
    • 如果您认为该答案不应该被埋葬,请随时为这个答案投票 :)
    • 但是我相信 Backbone.History.start 只在页面第一次加载时被调用,所以如果你导航到一个无效的路由而不刷新页面,这是行不通的。
    • @machineghost 如果您将答案更新到最新状态以使其有效,我将很高兴。我认为 router.trigger('404') 只需更改为 router.navigate('404', { 'trigger': true }) backbonejs.org/#Router-navigate @evilcelery 您是正确的,它仅在页面加载时调用,这将包括用户和 URL 导航所做的直接位置栏更改。问题是哈希更改是否会触发它。我需要做一些重构才能试一试。它可能不适用于所有情况,但我想知道这些情况是什么。
    • @evilcelery,好点子。但是,您的应用会将用户重定向到不存在的页面是什么情况?
    【解决方案3】:

    这个非常小的插件完成了它的工作:https://github.com/STRML/backbone.routeNotFound

    这是迄今为止我发现的解决这个问题的最优雅和最强大的方法,但是请记住,使用它会弄乱 Backbone 的内部结构。

    【讨论】:

      【解决方案4】:

      如果没有您当前路由代码的示例,我会假设确保您的 catch all 路线是最后一条路线应该适合您

      【讨论】:

      • 看起来您实际上需要通过 router.route() 将其添加为 last 路由,这就是问题所在。看起来像一个错误,在这里提交:github.com/documentcloud/backbone/issues/1463
      • @evilcelery:是的,如果你关心顺序,你必须使用route()添加路由,Backbone(至少在历史上)对对象的迭代顺序做了一些无效的假设,没有一致的顺序JavaScript 中的对象键。
      • 糟糕,我实际上把强调的词弄错了,原来你现在需要通过route()将它添加为first路由。
      • @muistooshort 是的,我注意到了,并认为他们使用一个对象很奇怪,似乎路由应该在数组中定义
      【解决方案5】:

      只需将其添加为列表中的最后一条路线即可。这样它只会被匹配为后备选项。

      【讨论】:

        【解决方案6】:

        您可以像这样将其破解到主干:

        var _loadUrl = Backbone.history.loadUrl;
        Backbone.history.loadUrl = function (fragment) {
            var result = _loadUrl.apply(Backbone.history, fragment);
            // the loadUrl returns false if no route was found.
            if(!result){
                // call 404 route on router if it exists.
                var handler = Backbone.history.handlers.filter( o => o.route.test("404") )
                if(handler.length) {
                    Backbone.history.navigate("/404")
        
                }
            }
        }
        

        然后在你的路由器中你可以这样做:

        var Router = Backbone.Router.extend({
            routes: {
                "404": "pageNotFound"
            },
        
            pageNotFound: function () {
                alert("trigger pageNotFound route")
            }
        });
        

        【讨论】:

        • 但这很讨厌,我也会接受答案:D
        【解决方案7】:

        我觉得这个不应该通过JavaScript来解决,应该是语言来解决,比如php。在服务器端处理文字,只要有条件就可以响应header,错误号为404

        【讨论】:

        • 这涉及使用hashs/hashbangs/pushstate 的客户端路由。服务器端不是答案。
        • @Trevor 问题不在于客户端如果服务端交互,那不是静态页面,怕是没有意义。
        • 在尝试回答有关问题之前,我认为您可能需要阅读一些关于使用 Backbone 进行客户端 URL 路由的内容:documentcloud.github.com/backbone/#Router
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多