我真的想利用Durandal的buildNavigationModel()
方法并将我的UI导航绑定到router.navigationModel
。
但在我的情况下,我基本上想要三个菜单项,它们都使用相同的底层视图和模块,但仅因参数而异。
// . . .
activate: function () {
var standardRoutes = [
{ route: 'home', title: 'KPI Home', iconClass: "glyphicon-home", moduleId: 'viewmodels/kpihome', nav: true },
{ route: 'summary(/:category)', title: 'Quotes', iconClass: "glyphicon-home", moduleId: 'viewmodels/summary', hash: "#summary/quotes", nav: true },
{ route: 'summary(/:category)', title: 'Pricing', iconClass: "glyphicon-home", moduleId: 'viewmodels/summary', hash: "#summary/pricing", nav: true },
{ route: 'summary(/:category)', title: 'Sales', iconClass: "glyphicon-home", moduleId: 'viewmodels/summary', hash: "#summary/sales", nav: true }
];
router
.map(standardRoutes)
.buildNavigationModel();
return router.activate();
}
因此,虽然哈希值不同,但我可以选择传递给摘要模块的activate
方法的类别,当我点击其他任一路由时,第一个匹配的路由{{ 1}}标志着真实。换句话说,isActive
使用路由模式而不是精确的哈希比较。
是否有人能够推荐替代/最佳实践方法,我可以重新使用路线模式和模块,并且仍然有一个有效的导航工具?
我目前的解决方案是仅创建一次路线并构建我自己的导航模型。
答案 0 :(得分:1)
经过一番挖掘后,我找到了解决这个问题的三种可能方案。
我将在下面的每个内容中聊聊我的意见,以及我如何找到解决方案。以下帖子对我帮助很大Durandal 2.0 - Child routers intended for nested menus?
虽然当你想创建存在于主路由器提供的视图中的子路由时,这很有意义,但我的要求是在包含所有子路由的shell级别上显示导航,始终可见并加载
"如果我们检查创建子路由的函数代码,我们将看到它创建新路由器并且只存储对父路由器的引用 - 父路由器(在大多数情况下是主路由器)没有对其子路由的引用#34;
因此,我的决定基于此(希望是正确的信息)以及我的案例,看起来它不起作用。
这有效并且在the article mentioned above中得到了很好的实施。但路由表是否与UI导航具有相同的问题?在某些情况下,确定它可以分享,但在我的情况下不是,所以我选择3,创建一个自定义导航模型。
我需要为导航项重复使用某些视图,以显示相同的摘要和详细信息视图,但是对于我将通过参数传递的不同类别和kpi。<\ n / p>
从路线表的角度来看,只有三条路线 - 到主视图的路线,摘要视图和详细视图。
从导航角度来看,有 n 导航项,具体取决于我想要显示摘要和详细视图的类别数和kpi。我会有效地为我想要展示的所有项目添加链接。
因此,我建立独立于路线表的导航模型是有道理的。
<强> utility\navigationModel.js
强>
定义导航模型并响应哈希更改以在activeHash
可观察中保留记录
define(["knockout", "utility/navigationItem"], function (ko, NavItem) {
var NavigationModel = function () {
this.navItems = ko.observableArray();
this.activeHash = ko.observable();
window.addEventListener("hashchange", this.onHashChange.bind(this), false);
this.onHashChange();
};
NavigationModel.prototype.generateItemUid = function () {
return "item" + (this.navItems().length + 1);
};
NavigationModel.prototype.onHashChange = function () {
this.activeHash(window.location.hash);
};
NavigationModel.prototype.findItem = function (uid) {
var i = 0,
currentNavItem,
findRecursive = function (uid, base) {
var match = undefined,
i = 0,
childItems = base.navItems && base.navItems();
if (base._uid && base._uid === uid) {
match = base;
} else {
for (; childItems && i < childItems.length; i = i + 1) {
match = findRecursive(uid, childItems[i]);
if (match) {
break;
}
}
}
return match;
};
return findRecursive(uid, this);
};
NavigationModel.prototype.addNavigationItem = function (navItem) {
var parent;
if (navItem.parentUid) {
parent = this.findItem(navItem.parentUid);
} else {
parent = this;
}
if (parent) {
parent.navItems.push(new NavItem(this, navItem));
}
return this;
};
return NavigationModel;
});
<强> utility\navigationItem.js
强>
表示导航项,具有导航特定属性,如iconClass
,子导航项navItems
,并计算确定它是否为有效导航isActive
define(["knockout"], function (ko) {
var NavigationItem = function (model, navItem) {
this._parentModel = model;
this._uid = navItem.uid || model.generateItemUid();
this.hash = navItem.hash;
this.title = navItem.title;
this.iconClass = navItem.iconClass;
this.navItems = ko.observableArray();
this.isActive = ko.computed(function () {
return this._parentModel.activeHash() === this.hash;
}, this);
}
return NavigationItem;
});
<强> shell.js
强>
定义路由表的标准路由并构建自定义导航。如果实施得当,这可能会调用数据服务来查找导航模型的类别和kpi
define([
'plugins/router',
'durandal/app',
'utility/navigationModel'
], function (router, app, NavigationModel) {
var customNavigationModel = new NavigationModel(),
activate = function () {
// note : routes are required for Durandal to function, but for hierarchical navigation it was
// easier to develop a custom navigation model than to use the Durandal router's buildNavigationModel() method
// so all routes below are "nav false".
var standardRoutes = [
{ route: '', moduleId: 'viewmodels/kpihome', nav: false },
{ route: 'summary(/:category)', moduleId: 'viewmodels/summary', hash: "#summary/quotes", nav: false },
{ route: 'kpidetails(/:kpiName)', moduleId: 'viewmodels/kpidetails', hash: "#kpidetails/quotedGMPercentage", nav: false }
];
router.map(standardRoutes);
// Fixed items can be added to the Nav Model
customNavigationModel
.addNavigationItem({ title: "KPI Home", hash: "", iconClass: "glyphicon-home" });
// items by category could be looked up in a database
customNavigationModel
.addNavigationItem({ uid: "quotes", title: "Quotes", hash: "#summary/quotes", iconClass: "glyphicon-home" })
.addNavigationItem({ uid: "sales", title: "Sales", hash: "#summary/sales", iconClass: "glyphicon-home" });
// and each category's measures/KPIs could also be looked up in a database and added
customNavigationModel
.addNavigationItem({ parentUid: "quotes", title: "1. Quoted Price", iconClass: "glyphicon-stats", hash: "#kpidetails/quotedPrice" })
.addNavigationItem({ parentUid: "quotes", title: "2. Quoted GM%", iconClass: "glyphicon-stats", hash: "#kpidetails/quotedGMPercentage" });
customNavigationModel
.addNavigationItem({ parentUid: "sales", title: "1. Quoted Win Rate", iconClass: "glyphicon-stats", hash: "#kpidetails/quoteWinRate" })
.addNavigationItem({ parentUid: "sales", title: "2. Tender Win Rate ", iconClass: "glyphicon-stats", hash: "#kpidetails/tenderWinRate" });
return router.activate();
};
return {
router: router,
activate: activate,
customNavigationModel: customNavigationModel
};
});
就是这样,相当数量的代码,但是一旦到位,它就可以很好地分离路由表和导航模型。剩下的就是将它绑定到UI,我使用小部件来做,因为它可以作为递归模板。
<强> widgets\verticalNav\view.html
强>
<ul class="nav nav-pills nav-stacked" data-bind="css: { 'nav-submenu' : settings.isSubMenu }, foreach: settings.navItems">
<li data-bind="css: { active: isActive() }">
<a data-bind="attr: { href: hash }">
<span class="glyphicon" data-bind="css: iconClass"></span>
<span data-bind="html: title"></span>
</a>
<div data-bind="widget: {
kind: 'verticalNav',
navItems: navItems,
isSubMenu: true
}">
</div>
</li>
</ul>
我并不是说这是最好的方法,但是如果你想分离路线表和导航模型的问题,那么它是一个潜在的解决方案:)