多级菜单

Multi-Level Menu

本文关键字:菜单 多级      更新时间:2023-09-26

我一直在想如何让这个动态菜单以比目前更干净的方式工作,我目前收到一个菜单项列表作为平面 XML 结构。

我在下面创建了一个对象,说明了数据在对象内部的外观,它对每个菜单项都有父子关系(为了便于阅读,我缩进了)

let Menu = [
  {
    DisplayName  : "Menu1",
    href         : "Menu1.aspx",
    MenuID       : "1",
    ParentMenuID : "?",
    Position     : "1",
    UserTypeCode : "99"
  },
      {
        DisplayName  : "Menu-1-1",
        href         : "Menu1.aspx",
        MenuID       : "2",
        ParentMenuID : "1",
        Position     : "1",
        UserTypeCode : "99"
      },
      {
        DisplayName  : "Menu-1-2",
        href         : "Menu1.aspx",
        MenuID       : "3",
        ParentMenuID : "1",
        Position     : "2",
        UserTypeCode : "99"
      },
  {
    DisplayName  : "Menu2",
    href         : "Menu2.aspx",
    MenuID       : "4",
    ParentMenuID : "?",
    Position     : "2",
    UserTypeCode : "99"
  },
      {
        DisplayName  : "Menu2-1",
        href         : "Menu1.aspx",
        MenuID       : "5",
        ParentMenuID : "4",
        Position     : "1",
        UserTypeCode : "99"
      },
      {
        DisplayName  : "Menu2-2",
        href         : "Menu1.aspx",
        MenuID       : "6",
        ParentMenuID : "4",
        Position     : "2",
        UserTypeCode : "99"
      },
          {
            DisplayName  : "Menu2-2-1",
            href         : "Menu1.aspx",
            MenuID       : "7",
            ParentMenuID : "6",
            Position     : "1",
            UserTypeCode : "99"
          }
];

想知道我如何动态创建菜单对象(使用我认为是理想的递归函数),而无需我目前有点混乱的解决方案,即需要为菜单的每个级别使用不同的函数,这是我的代码目前的样子,它仅限于菜单的 3 个级别

我想要的是一个不错的功能,它可以接受任意数量的菜单级别

function createRoot(){
    // Initially map all root elements
    Menu.map((item, index) => {
        if (item.ParentMenuID === "?"){
            // If the the next menu item is a child of this root
            if (Menu[index+1].ParentMenuID === item.MenuID){
                // Generate boilerplate dropdown code + then retrieve it's children
                htmlStr += `<li class="dropdown-submenu"><a class="test" data-menuID="`+item.MenuID+`" data-menuitem="`+item.href+`" href="#">`+item.DisplayName+`<span class="caret"></a>`
                    htmlStr += `<ul class="dropdown-menu">`
                        GetLevel1(item);
                    htmlStr += `</ul>`
                htmlStr += `</li>`
            // Otherwise it's just a normal menu item
            } else {
                htmlStr += `<li><a class="test" data-menuID="`+item.MenuID+`" data-menuitem="`+item.href+`" href="#">`+item.DisplayName+`</a></li>`
            }
        }

    });
    $('#user-menu-list').html(htmlStr);
      // Setup event on list items
      $('.dropdown-submenu a.test').on("click", function(e){
        $(this).next('ul').toggle();
        e.stopPropagation();
        e.preventDefault();
      });
}
function GetLevel1(item){
    Menu.map((subItem, index) => {
        if (index < Menu.length-1){
        console.log(index);
            // If the current item is a child of the root
            if (subItem.ParentMenuID === item.MenuID){
                // If the the next item is a child of this root
                if (Menu[index+1].ParentMenuID === subItem.MenuID){
                    htmlStr += `<li class="dropdown-submenu"><a class="test" data-menuID="`+subItem.MenuID+`" data-menuitem="`+subItem.href+`" href="#">`+subItem.DisplayName+`<span class="caret"></a>`
                        htmlStr += `<ul class="dropdown-menu">`
                            GetLevel2(subItem);
                        htmlStr += `</ul>`
                    htmlStr += `</li>`
                } else {
                    htmlStr += `<li><a class="test" data-menuID="`+subItem.MenuID+`" data-menuitem="`+subItem.href+`" href="#">`+subItem.DisplayName+`</a></li>`
                }
            }
        }

    });
}
function GetLevel2(item){
    Menu.map((subItem, index) => {
        console.log("INDEX: "+index);
        // If the current item is a child of the root
        if (subItem.ParentMenuID === item.MenuID){
            htmlStr += `<li><a class="test" data-menuID="`+subItem.MenuID+`" data-menuitem="`+subItem.href+`" href="#">`+subItem.DisplayName+`</a></li>`
        }
    });
}
createRoot();

这是一个完整的粘贴链接,我的菜单目前正在运行:http://pastebin.com/ektBQ7kd

任何帮助将不胜感激!

我的递归能力有点生疏,可以改进,我会做这样的事情,首先浏览所有菜单,将孩子菜单添加到他们的父母。

第一阶段完成后,我在一个对象中有菜单和子菜单,您可以再次执行递归并构建菜单。

像这样:

var Menu = [{
  DisplayName: "Menu1",
  href: "Menu1.aspx",
  MenuID: "1",
  ParentMenuID: "?",
  Position: "1",
  UserTypeCode: "99"
}, {
  DisplayName: "Menu-1-1",
  href: "Menu1.aspx",
  MenuID: "2",
  ParentMenuID: "1",
  Position: "1",
  UserTypeCode: "99"
}, {
  DisplayName: "Menu-1-2",
  href: "Menu1.aspx",
  MenuID: "3",
  ParentMenuID: "1",
  Position: "2",
  UserTypeCode: "99"
}, {
  DisplayName: "Menu2",
  href: "Menu2.aspx",
  MenuID: "4",
  ParentMenuID: "?",
  Position: "2",
  UserTypeCode: "99"
}, {
  DisplayName: "Menu2-1",
  href: "Menu1.aspx",
  MenuID: "5",
  ParentMenuID: "4",
  Position: "1",
  UserTypeCode: "99"
}, {
  DisplayName: "Menu2-2",
  href: "Menu1.aspx",
  MenuID: "6",
  ParentMenuID: "4",
  Position: "2",
  UserTypeCode: "99"
}, {
  DisplayName: "Menu2-2-1",
  href: "Menu1.aspx",
  MenuID: "7",
  ParentMenuID: "6",
  Position: "1",
  UserTypeCode: "99"
}];
var main = [];
function getSiblins(currentNode, currentId) {
  if (!currentId) {
    currentNode.children = currentNode.children || new Array();
    return getSiblins(currentNode, currentNode.MenuID)
  } else {
    for (var j = 0; j < Menu.length; j++) {
      if (Menu[j].ParentMenuID == currentId) {
        currentNode.children.push(Menu[j]);
      }
    }
  }
  if (currentNode.ParentMenuID == "?") {
    //root menu
    main.push(currentNode);
  }
}
for (var i = 0; i < Menu.length; i++)
  getSiblins(Menu[i]);
function prepareMenu(currentMenu) {
  var appendHtml = "<li>" + currentMenu.DisplayName + "</li>"
  for (var i = 0; i < currentMenu.children.length; i++) {
    appendHtml = appendHtml + "<ul class='children'>" + prepareMenu(currentMenu.children[i]) + "</ul>";
  }
  return appendHtml;
}
var menuHtml = "";
for (var j = 0; j < main.length; j++) {
  menuHtml += prepareMenu(main[j]);
}
document.getElementById("finalMenu").innerHTML = menuHtml;
.children li{
  color: blue;
}
.children .children li {
  color: green;
}
<ul id="finalMenu">
</ul>