如何使用JavaScript从指定JSON数组创建层级菜单?
Alright, let's walk through how to turn that flat array of menu items into a proper hierarchical menu (with submenus) using JavaScript. We'll split this into two core steps: structuring the data into a tree, then rendering it as HTML.
Step 1: Convert Flat JSON to Hierarchical Tree Structure
First, we need to transform the flat array into a nested tree where each parent menu item has its child items attached. This makes it easy to render submenus later.
Here's the code to do that:
const menuItems = [ { "page_id":"102608802958096849","title":"Submenu 1 1","page_order":1,"parent_id":"305280635460611248","layout":"header","page_url":"submenu-1-1.html" }, { "page_id":"207782958260361106","title":"Submenu 2 1","page_order":1,"parent_id":"196241715470310788","layout":"header","page_url":"submenu-2-1.html" }, { "page_id":"305280635460611248","title":"Submenu 1","page_order":1,"parent_id":"308333626876055885","layout":"header","page_url":"submenu-1.html" }, { "page_id":"196241715470310788","title":"Submenu 2","page_order":2,"parent_id":"308333626876055885","layout":"header","page_url":"submenu-2.html" }, { "page_id":"308333626876055885","title":"Main Menu","page_order":0,"parent_id":null,"layout":"header","page_url":"main.html" } ]; // Create a map to quickly look up menu items by page_id const menuMap = {}; const rootMenuItems = []; // Initialize each item with a children array and add to the map menuItems.forEach(item => { menuMap[item.page_id] = { ...item, children: [] }; }); // Link child items to their parent items menuItems.forEach(item => { const parentId = item.parent_id; if (!parentId || !menuMap[parentId]) { // Items with no valid parent go into the root menu rootMenuItems.push(menuMap[item.page_id]); } else { // Attach child to its parent's children array menuMap[parentId].children.push(menuMap[item.page_id]); } }); // Sort menu items (and their children) by page_order to keep the correct sequence const sortMenuByOrder = (menu) => { menu.sort((a, b) => a.page_order - b.page_order); menu.forEach(item => { if (item.children.length > 0) { sortMenuByOrder(item.children); } }); }; sortMenuByOrder(rootMenuItems);
Key Notes:
- menuMap: This lets us look up any parent item in O(1) time instead of looping through the array every time, which is way more efficient.
- children Array: We add a
childrenproperty to each item to store its submenu items. - Sorting: The
sortMenuByOrderfunction ensures items appear in the correct sequence based onpage_order, even for nested submenus.
Step 2: Render the Hierarchical Menu as HTML
Now that we have our nested tree structure, we can render it into a functional HTML menu using a recursive function (perfect for handling any number of submenu levels).
Here's how to generate and insert the menu into the DOM:
// Recursive function to build HTML from the menu tree const generateMenuHTML = (menu) => { if (!menu || menu.length === 0) return ''; let html = '<ul class="menu">'; menu.forEach(item => { html += `<li class="menu-item"> <a href="${item.page_url}">${item.title}</a>`; // If the item has children, recursively generate the submenu if (item.children.length > 0) { html += generateMenuHTML(item.children); } html += '</li>'; }); html += '</ul>'; return html; }; // Insert the menu into your page const menuContainer = document.getElementById('menu-container'); if (menuContainer) { menuContainer.innerHTML = generateMenuHTML(rootMenuItems); }
Add Some Basic CSS (Optional)
To make the submenus visible on hover, add this simple CSS:
.menu { list-style: none; padding: 0; display: flex; background: #f0f0f0; } .menu-item { position: relative; padding: 10px 20px; } .menu-item ul { position: absolute; top: 100%; left: 0; display: none; background: white; list-style: none; padding: 0; min-width: 150px; } .menu-item:hover ul { display: block; }
This will give you a basic horizontal menu with dropdown submenus that appear on hover.
内容的提问来源于stack exchange,提问作者Ha Doan Thanh

