【问题标题】:Backbone multi routers trap - sub router handler doesent invoke骨干多路由器陷阱 - 子路由器处理程序不调用
【发布时间】:2014-10-17 09:48:35
【问题描述】:

陷入了骨干路由器的陷阱。想象一下,我有 2 个主干路由器:

1) RootRouter - 只有一个路由和唯一的职责 - 使用 RequireJS 加载 subRouter 并实例化它。

var RootRouter = Backbone.Router.extend({
    routes: {
        '*all': 'invokeSubModule'
    },
    invokeSubModule: function(route, args) {
        require(['SubRouter'], function(subRouter) {
            new subRouter()
        })
    }
});

2) SubRouter - 带有路由哈希和处理程序的标准 BB 路由器。

var SubRouter = Backbone.Router.extend({
    routes: {
        'some/bar': 'doBar',
        'some/foo': 'doFoo'
    },
    doBar: function() { ... },
    doFoo: function() { ... }
});

我从some/bar URL 启动应用程序。 在启动时 RootRouter 实例化和 Backbone.History 启动。 正如预期的那样 RootRouter - 匹配任何 URL 并触发 invokeSubModule - 异步加载和 SubRouter 实例按预期工作,但问题与 some/bar 相关联 SubRouter 处理程序不会触发,因为页面 URL 与上一个相比没有变化route.

寻找解决方案我只找到了你在历史开始之前加载子路由器的情况的答案,但在我的情况下它没用。

所以经过一番挖掘后,我找到了解决方案 - 扩展 Backbone.Route 并覆盖 route 方法,以便在 Backbone.getHash() 等于操作的路由方法时调用处理程序。

Backbone.Router.extend({
     route: function(route, name, callback) {
        ...
        if (!callback) callback = this[name];

        /* run handler immediately if route we add is the current URL fragment */
        if(routeRegexp.test(Backbone.history.getHash()) ) {
            this.execute(callback, this._extractParameters(routeRegexp, routeStr));
        }

        Backbone.history.route(route, function(fragment) {
            ....
        });

        return this;
    }
})

所以我很困惑,这只是一个 hack,将来可能会导致错误。 因此,寻找解决此类问题的最佳实践并批评我的解决方案。

还期望回答如何在没有 RootRouter 的情况下管理路由器延迟加载,因为在这种情况下,不会触发第一个 route

【问题讨论】:

  • 您是否尝试像这样订阅RootRouter route 事件:RootRouter.on("route:invokeSubModule", function(url) { SubRouter.navigate(url); })
  • 它不会工作,因为navigate 不会触发回调,因为片段仍然相同。当前的解决方案有效,但我不确定它是否打破了主干思想,它不是再次发明自行车

标签: backbone.js


【解决方案1】:

我能够在不破解骨干路由内部的情况下复制您需要的行为,但我必须在初始化时做一些事情。

首先我将创建主路由器并使用静默选项启动主干历史记录 = true

var mainRouter = new RootRouter();
Backbone.history.start({silent: true});

这将启动主干历史记录,但不会路由当前 url。 然后我得到了当前的片段并将其保存以备后用,然后导航到基本 url,然后返回到原始片段

var fragment = Backbone.history.fragment;
mainRouter.navigate('reset',true);
mainRouter.navigate(fragment, true); 

这种方法的不好的一面是你需要在启动时进行 2 次路由

更新:

低于完整样本

<html><head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title> sample </title>

  <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
  <script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
  <script type="text/javascript" src="http://backbonejs.org/backbone-min.js"></script>


  <style type="text/css">

  </style>

  <script>
    var RootRouter = Backbone.Router.extend({
    routes: {
        '*all': 'invokeSubModule',
        'reset': 'invokeSubModule',
    },
    invokeSubModule: function(route, args) {
        new SubRouter();
    },

    navigate: function () {
                Backbone.Router.prototype.navigate.apply(this, arguments);
            },

    execute: function(callback, args) {
                console.log('execute root');
                Backbone.Router.prototype.execute.apply(this, arguments);
                console.log ('current fragment ' + Backbone.history.fragment);
            }
    });

    var SubRouter = Backbone.Router.extend({
    routes: {
        'some/bar': 'doBar',
        'some/foo': 'doFoo'
    },

    navigate: function () {
                Backbone.Router.prototype.navigate.apply(this, arguments);
            },
    execute: function(callback, args) {
                console.log('execute sub');
                Backbone.Router.prototype.execute.apply(this, arguments);
                console.log ('current fragment ' + Backbone.history.fragment);
            },
    doBar: function() { 
        $('#content').html('').append('<p>BAR</p>'); 
    },
    doFoo: function() { 
        $('#content').html('').append('<p>FOO</p>'); 
    }
});

    $(document).ready(function(){
        var mainRouter = new RootRouter();
        Backbone.history.start({silent: true});
        var fragment = Backbone.history.fragment;
        mainRouter.navigate('#',true);
        mainRouter.navigate(fragment, true);

        $('a').click(function(){
            mainRouter.navigate($(this).attr('href'));
        });
    });
  </script>

</head>
<body>
    <a id='home' href="#">home</a></br>
    <a id='foo' href="#/some/foo">foo</a></br>
    <a id='bar' href="#/some/bar">bar</a></br>
    <div id='content'>HOME</div>
</body></html>

【讨论】:

  • 但是这种方法也会迫使我在每个模块加载时重置历史记录?
  • 不,您不必在每个模块加载时重置,我只需导航到文档就绪事件上的重置路由,因此我确定在加载子视图之前加载子路由器,您可以检查片段变量以加载正确的子路由器
  • 我会用完整的代码更新答案供你测试
  • 谢谢,明白你的想法,接受作为替代解决方案。
猜你喜欢
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 2013-08-11
  • 2012-06-12
  • 1970-01-01
  • 1970-01-01
  • 2013-02-21
  • 1970-01-01
相关资源
最近更新 更多