7

我刚刚开始与 Durandal 合作,所有的部分都已经到位,并且正在使用 Hot Towel 模板来加快速度。

让我难过的一件事是如何创建比按钮组更复杂的分层导航系统。这就是我想要的结果:

ABC
A1 B1 C1
A2 B2 C2

A、B 和 C 是没有附加路线的顶级菜单 - 它们只是占位符。我将拥有 A1、A2、B1、B2、C1 和 C2 的视图和视图模型,并且需要将这些哈希标记作为活动链接。

我现在最好的想法是将父菜单附加到每个路由的 url 中,并在 nav.html 中有代码,根据解析 url 将每个节点动态添加到适当的父级中。为了完全动态,它将动态添加父节点和子节点。

        {
          url: 'A_A1',
          moduleId: 'viewmodels/A_A1',
          name: 'A1',
          visible: true
        }

我已经用 Durandal 搜索了很多分层导航示例,但还没有看到任何东西。是否有将导航功能扩展到简单的一维列表之外的最佳实践?我是否忽略了路由器中的一些我没有看到的功能,这些功能可以让我在不将层次结构信息嵌入视图名称的情况下执行此操作?

编辑:我只是将答案标记为正确,即使我对所提出的任何一种解决方案都不满意。在选择一个框架来抽象和分开的逻辑,演示和控制时,再次开始合并这些构造似乎只是为了提供更多的基本导航外壳。我已经将我的开发工作转移到了 angularjs,这样的事情变得更加直观并且可以保持分离。希望 Durandal 能在不久的将来更进一步,我肯定会为未来的项目重新评估它。

4

2 回答 2

6

您可以将它们硬编码到您的 shell 视图中,但如果您不想这样做,您可以这样做 -

在您看来,使用 /# 创建一个不工作的锚点,它什么都不做,下拉 a 路由,另一个下拉 b 路由。

        <div class="nav-collapse collapse main-nav">
            <div class="btn-group">
                <a class="btn" href="/#">
                    <span class="text">A Routes</span> </a>
                <button class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
                    <ul class="dropdown-menu pull-right">
                        <!-- ko foreach: aRoutes -->
                        <li data-bind="css: { active: isActive }">
                            <a data-bind="attr: { href: hash }, html: name"></a>
                        </li>
                        <!-- /ko -->
                    </ul>
            </div>
            <div class="btn-group">
                <a class="btn" href="/#">
                    <span class="text">B Routes</span> </a>
                <button class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
                    <ul class="dropdown-menu pull-right">
                        <!-- ko foreach: bRoutes -->
                        <li data-bind="css: { active: isActive }">
                            <a data-bind="attr: { href: hash }, html: name"></a>
                        </li>
                        <!-- /ko -->
                    </ul>
            </div>
      </div>

为你的 shell 视图模型中的路由创建一些计算的 observables

    var aRoutes = ko.computed(function () {
        return router.allRoutes().filter(function (r) {
            return r.settings.aroute;
        });
    });

    var bRoutes = ko.computed(function () {
        return router.allRoutes().filter(function (r) {
            return r.settings.broute;
        });
    });

在您的路线定义中-

 {
     url: 'a1',
     moduleId: 'viewmodels/a1',
     name: 'A1',
     visible: false,
     settings: {aroute: true}
 },

这会将您的所有路由设置为 false,然后为它们提供设置为 true 的 aroute 的另一个属性。计算出的过滤器只过滤设置为 true 的路由。

于 2013-07-16T01:44:10.437 回答
3

在阅读了这篇文章后,我设计了一个通用的解决方案。使用此解决方案,您可以将任何路线动态添加到导航中的下拉菜单。

在我指定路线的 main.js 中,我添加了一个函数,用于将子菜单对象映射到主导航路线的设置对象。

function mapSubNav(parentRouteInfo) {
    var subroutes = [];
    var length = arguments.length;
    for (var i = 0; i < length; i++) {
        subroutes.push(arguments[i]);
    }
    parentRouteInfo.settings.subroutes = subroutes;
}

var page = router.mapNav('page', null, 'Page'),
    sub1 = router.mapRoute('page/sub1', null, 'Sub1'),
    sub2 = router.mapRoute('page/sub2', null, 'Sub2');
mapSubNav(nav, sub1, sub2);

解释:

router 函数mapNav返回一个如下所示的路由定义:

{
    url:'flickr', //you provided this
    name: 'Flickr', //derived
    moduleId: 'flickr', //derived
    caption: 'Flickr', //derived (uses to set the document title)
    settings: {}, //default,
    hash: '#/flickr', //calculated
    visible: true, //from calling mapNav instead of mapRoute
    isActive: ko.computed //only present on visible routes to track if they are active in the nav
}

辅助函数mapSubNav将在设置对象的下拉菜单中放置一个对您希望出现的路由的引用列表。在此示例中,结果将是:

{
    url:'page',
    name: 'Page',
    moduleId: 'page',
    caption: 'Page',
    settings: { subroutes: [nav, sub1, sub2] },
    hash: '#/page',
    visible: true,
    isActive: ko.computed
}

我将我的 shell 视图模型扩展为如下所示:

define(function (require) {
    var router = require('durandal/plugins/router');
    var app = require('durandal/app');

    var ViewModel = function () {
        var self = this;
        self.router = router;
        self.dataToggle = function (route) {
            return !!route.settings.subroutes ? 'dropdown' : '';
        };
        self.html = function (route) {
            return !!route.settings.subroutes ? route.name + ' <b class="caret"></b>' : route.name;
        };
        self.hash = function (route) {
            return !!route.settings.subroutes ? '#' : route.hash;
        };
        self.divider = function (route, parent) {
            system.log('Adding', route, 'to dropdown', 'Parent', parent);
            return route.hash === parent.hash;
        };
        self.activate = function () {
            return router.activate('welcome');
        }
    };

    return new ViewModel();
});

笔记:

中的额外函数shell.js将决定应该将哪些属性添加到导航中的 DOM 元素。


最后,我编辑了我的 shell 视图,使其看起来像这样;

<div class="nav-collapse collapse">
    <ul class="nav navbar-nav" data-bind="foreach: router.visibleRoutes()">
        <li data-bind="css: { active: isActive, dropdown: !!settings.subroutes }">
            <a data-bind="css: { 'dropdown-toggle': !!settings.subroutes },
                          attr: { href: $root.hash($data), 'data-toggle': $root.dataToggle($data) },
                          html: $root.html($data)"></a>
            <ul data-bind="foreach: settings.subroutes" class="dropdown-menu">
                <li><a data-bind="attr: { href: hash },
                                  html: name"></a></li>
                <li data-bind="css: { divider: $root.divider($data, $parent) }"></li>
            </ul>
        </li>
    </ul>
</div>

结果:

最终结果是一个带有下拉切换的菜单项。下拉菜单将包含一个到父路由的链接和一个到子路由的链接。像这样的东西:

---------------------------------------------
 Menu items... | Page v | More menu items...
---------------------------------------------
               | Page   |
               ----------
               | Sub 1  |
               | Sub 2  |
               ----------

jQuery不允许您将路由映射到下拉切换按钮,这就是为什么我让父路由在子路由列表中保留对自身的引用在导航中仍然存在指向父路由的链接。

于 2013-08-13T14:21:05.943 回答