在阅读了这篇文章后,我设计了一个通用的解决方案。使用此解决方案,您可以将任何路线动态添加到导航中的下拉菜单。
在我指定路线的 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不允许您将路由映射到下拉切换按钮,这就是为什么我让父路由在子路由列表中保留对自身的引用在导航中仍然存在指向父路由的链接。