使用DurandalJS构建到同一模块的多个导航路由

时间:2014-06-16 10:03:48

标签: durandal durandal-2.0

我真的想利用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使用路由模式而不是精确的哈希比较。

是否有人能够推荐替代/最佳实践方法,我可以重新使用路线模式和模块,并且仍然有一个有效的导航工具?

我目前的解决方案是仅创建一次路线并构建我自己的导航模型。

1 个答案:

答案 0 :(得分:1)

经过一番挖掘后,我找到了解决这个问题的三种可能方案。

  1. 使用子路由器
  2. 在路由中使用自定义标识符来描述子路由并将这些路由解析为路由表
  3. 将路由留给路由表并创建自定义导航模型
  4. 我将在下面的每个内容中聊聊我的意见,以及我如何找到解决方案。以下帖子对我帮助很大Durandal 2.0 - Child routers intended for nested menus?

    使用子路由器

    虽然当你想创建存在于主路由器提供的视图中的子路由时,这很有意义,但我的要求是在包含所有子路由的shell级别上显示导航,始终可见并加载

    根据the article mentioned above

      

    "如果我们检查创建子路由的函数代码,我们将看到它创建新路由器并且只存储对父路由器的引用 - 父路由器(在大多数情况下是主路由器)没有对其子路由的引用#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>
    

    我并不是说这是最好的方法,但是如果你想分离路线表和导航模型的问题,那么它是一个潜在的解决方案:)