如何在knockout viewmodel中处理嵌套菜单

时间:2014-02-25 10:31:58

标签: javascript jquery knockout.js

我在我的项目中使用knockoutjs。我有一个场景,我必须在我的viewmodel中创建一个嵌套菜单,我这样做:

self.menu = [
    { 
         name: 'Services', 
         sub: [{ name: 'Service-A' }, { name: 'Service-B' }] 
    },
    // etc
];

self.chosenMenu = ko.observable();

self.goToMenu = function (main, sub) {

    var selectedMenu = {
        main: main,
        sub: sub
    };

    self.chosenMenu(selectedMenu);
};

我的观点:

<ul class="nav navbar-nav menuitems col-md-8" data-bind="foreach: menu">
    <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown">
          <span data-bind="text: name"></span></a>
        <ul class="dropdown-menu" role="menu" data-bind="foreach: sub">
            <li>
                <a href="javascript:void(0);" data-bind="text: name, 
                   click: function() { $root.goToMenu($parent, $data); }">
                </a> 
            </li>
        </ul>
    </li>
</ul>

但是,我觉得这种创建嵌套菜单的方法并不好,因为如果我想以编程方式继续使用任何菜单项,那么他的方法是不可能的?

有人可以建议我处理这种情况的好方法吗?

2 个答案:

答案 0 :(得分:0)

确保每个菜单项都有唯一标识符。对于您已经提供name的示例数据就足够了,但您可能需要向菜单项视图模型添加fullPath属性。

您的goToMenu函数现在只能使用一个参数:uniqueMenuIdentifier,并递归所有菜单项以找到正确的参数,如下所示:

function findMenuItem(menuList, uniqueMenuIdentifier) {
    for (var i = 0; i < menuList.length; i++) {
        if (menuList[i].name === uniqueMenuIdentifier) {
            return menuList[i];
        }
        if (!!menuList[i].sub) {
            var subItem = findMenuItem(menuList[i].sub, uniqueMenuIdentifier);
            if (!!subItem) {
                return subItem;
            }
        }
    }
    return null;
}

self.goToMenu = function (menuItem) {
    var uniqueMenuIdentifier = menuItem.name;
    var item = findMenuItem(self.menu, uniqueMenuIdentifier);
    self.chosenMenu(item);
}

这允许在锚标记中进行更简单的绑定:

<a href="javascript:void(0);" data-bind="text: name, click: $root.goToMenu">

请参阅this fiddle了解演示。

从这里你也可以猜到甚至可以直接设置chosenMenu

// No longer needed:
//function findMenuItem(menuList, uniqueMenuIdentifier) { }

self.goToMenu = function (menuItem) {
    self.chosenMenu(menuItem);
}

请参阅this fiddle了解演示。

答案 1 :(得分:0)

昨天我遇到了类似的情况。您可以查看我的解决方案 Is there any knockout plugin for showing a nested context menu?。重点是我使用模板绑定能够构建任何深度的分层菜单。