【问题标题】:Durandal 2.0 - Child routers intended for nested menus?Durandal 2.0 - 用于嵌套菜单的子路由器?
【发布时间】:2013-10-29 07:17:08
【问题描述】:

我正在构建一个应用程序,并希望显示一个 2 层菜单,这两个层级始终可用。 Durandal 2.0 introduced their new router,支持“子路由器”,可以更轻松地进行深度链接。

我的问题 - 我可以永久加载我的“子”导航路线(并在父不活动时呈现子菜单),还是“子路由器”设计旨在懒惰 -一旦要评估深层链接,就加载它们以评估它们?

Durandal 示例显示主导航注册一个 splat 路由,然后当该视图模型被加载/激活时,子路由被注册。

例如:在 Durandal 2.0 提供的示例中,mian nev 注册在shell.js

router.map([
                { route: ['', 'home'], moduleId: 'hello/index', title: 'Validation test', nav: true },
                { route: 'knockout-samples*details',    moduleId: 'ko/index',               title: 'Knockout Samples',  nav: true, hash: '#knockout-samples' }
            ]).buildNavigationModel()
              .activate();

然后ko/index.js 视图模型注册孩子(在activate())

var childRouter = router.createChildRouter()
        .makeRelative({
            moduleId:'ko',
            fromParent:true
        }).map([
            { route: '',                moduleId: 'helloWorld/index',       title: 'Hello World',           type: 'intro' },
            { route: 'helloWorld',      moduleId: 'helloWorld/index',       title: 'Hello World',           type: 'intro',      nav: true},
            { route: 'clickCounter',    moduleId: 'clickCounter/index',     title: 'Click Counter',         type: 'intro',      nav: true}
        ]).buildNavigationModel();

而我希望在一个地方定义我的路线,例如:

 var routes = [
   { route: ['', 'home'], 
        moduleId: 'hello/index', 
        title: 'Validation test', 
        nav: true },
   { route: 'knockout-samples*details',    
        moduleId: 'ko/index',
        moduleRootId: 'ko', // Custom property to make child routes easier              
        title: 'Knockout Samples',  
        nav: true, 
        hash: '#knockout-samples',
        childRoutes: [
            { route: '',                moduleId: 'helloWorld/index',       title: 'Hello World',           type: 'intro' },
            { route: 'helloWorld',      moduleId: 'helloWorld/index',       title: 'Hello World',           type: 'intro',      nav: true},
            { route: 'clickCounter',    moduleId: 'clickCounter/index',     title: 'Click Counter',         type: 'intro',      nav: true}
        ]}
   ])

我正在努力的部分是注册子路线,并在导航到它们时让它们正确评估。 (渲染菜单将在稍后进行......)

// Load routes              router.map(routes.navRoutes).buildNavigationModel().mapUnknownRoutes(function(instruction)
{
    logger.logError('No Route Found', instruction.fragment, 'main', true);
});

// Try load child routes...
$.each(routes.navRoutes, function(index, parentRoute) {
     if (!parentRoute.childRoutes) {
                return;
            }

            var childRouter = router.createChildRouter()
                .makeRelative({
                    moduleId: parentRoute.moduleRootId,
                    fromParent: true // also tried false + non-splat routes...
                }).map(parentRoute.childRoutes).buildNavigationModel();
        });

我在渲染此导航时遇到了各种错误。尝试计算哈希(来自未激活的父级或子级)时,主要是内部 router.js 错误 - 因此所有哈希都已定义。

一旦我用它来映射导航,子路线似乎无法访问 - 他们只是加载主 splat 页面而没有错误。

所以我想知道我是否以正确的方式处理这件事? (预先注册所有子路由,目标是渲染一个 2 层菜单)。

我认为后备方案是使用 Durandal 1.2 answer about subrouting 之类的东西,使用平面路由注册、自定义“isSameItem”函数和计算的 observables 的组合来呈现 2 层导航。

【问题讨论】:

    标签: durandal hottowel durandal-navigation


    【解决方案1】:

    希望可以帮到你。

    您可以永久加载“子”路由器吗?

    据我所知,您不能(或者说没有简单的方法可以实现)。子路由器旨在为特定视图提供子路由功能 - 您可以将它们视为 Durandal 视图中的 Durandal 导航。如果我们检查 Durandal 页面上的示例代码,我们可以很容易地看到子路由生命周期与给定视图相关联。更重要的是,如果我们检查创建子路由的函数代码,我们会看到它创建了新路由器并且只存储对父路由器的引用 - 父路由器(在大多数情况下是主路由器)没有对其子路由器的引用

    router.createChildRouter = function() {
                var childRouter = createRouter();
                childRouter.parent = router;
                return childRouter;
            }; 
    

    如何在主路由器中实现多级路由?

    我过去也遇到过类似的问题,但使用的是旧版本的 Durandal。对于这个问题,我从头开始,您给出并修改了一点 - 我摆脱了 splat 路线,因为它打算与子路线一起使用,我的解决方案不会使用它们。

    var routes = [
                    {
                        route: ['', 'home'],
                        moduleId: 'viewmodels/home',
                        title: 'Validation test',
                        nav: true
                    },
                    {
                        route: 'knockout-samples',
                        moduleId: 'viewmodels/ko/index',
                        moduleRootId: 'viewmodels/ko', // Custom property to make child routes easier              
                        title: 'Knockout Samples',
                        nav: true,
                        hash: '#knockout-samples',
                        childRoutes: [
                            { route: 'simpleList', moduleId: 'simpleList', title: 'SimpleList',  nav: true, hash : 'simpleList' },
                            { route: 'clickCounter', moduleId: 'clickCounter', title: 'Click Counter', nav: true, hash : 'clickCounter' }
                        ]
                    }
                ];
    

    下一步是将这个用户友好的定义转换为可以在主路由器中轻松注册的路由表。

    $.each(routes, function(index, route) {
                    if (route.childRoutes === undefined)
                        return
                    $.each(route.childRoutes, function(index, childRoute) {
                        childRoute.route = route.route + '/' + childRoute.route;
                        childRoute.moduleId = route.moduleRootId + '/' + childRoute.moduleId;
                        childRoute.title = route.title + '/' + childRoute.title;
                        childRoute.hash = route.hash + '/' + childRoute.hash;
                        childRoute.parent = route.moduleRootId;
                    });
                    routes = routes.concat(route.childRoutes);
                });
    

    最后一步是标准注册路由器并激活它。

    return router.map(routes)
                    .buildNavigationModel()
                    .activate();
    

    如何渲染寄存器路由以保留多级布局?

    我的代码适用于 Bootstrap 2.3.0,并将多级菜单呈现为下拉按钮。当路线没有子路线(简单路线也是如此)并且没有父路线(其第一级导航)时,将呈现为简单按钮。如果路由有子路由,则将其呈现为下拉按钮,并将子路由添加到下拉列表中。

    <div class="btn-group" data-bind="foreach: router.navigationModel">
                <!-- ko if: $data.childRoutes === undefined && $data.parent === undefined -->
                    <a data-bind="css: { active: isActive }, attr: { href: hash }, text: title" class="btn btn-info" href="#"/>
                <!-- /ko -->
                <!-- ko if: $data.childRoutes !== undefined -->
                <div class="btn-group btn-info">
                    <a data-bind="css: { active: isActive }, attr: { href: hash }, text: title" class="btn btn-info" href="#"/>
                    <button class="btn btn-info dropdown-toggle" data-toggle="dropdown">
                        <span class="caret"/>
                    </button>
                    <ul class="dropdown-menu" data-bind="foreach: childRoutes">
                        <a data-bind="css: { active: isActive }, attr: { href: hash }, text: title" class="btn btn-info" href="#"/>
                    </ul>
                </div>
                <!-- /ko -->
            </div>
    

    样式可能需要稍微修饰一下,但整体逻辑已经完成。

    【讨论】:

    • 我过去使用不同的方法来处理路由器对象的属性,但我认为这更优雅一些,我真的很喜欢这个解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 2019-02-24
    • 1970-01-01
    相关资源
    最近更新 更多