You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Vanilla JS/JQuery按层级嵌套处理对象数组的问题

菜单层级渲染问题解决方案

问题描述

需要处理对象数组并渲染成层级菜单,要求先显示主分类(Desserts、Water、Tea),点击主分类展开对应子分类。当前存在两个问题:

  1. 主分类完全不显示
  2. 无法按层级嵌套关系访问元素并实现独立的类切换

问题1:主分类不显示的原因

你当前调用addElements(menuEl, menu[0].groups)时,传入的是第一个主分类的子分类数组,而非整个主分类数组menu。这导致代码只渲染了Desserts下的子分类,完全跳过了所有主分类的渲染。

问题2:层级元素访问与交互实现方案

要实现层级展开/收起且独立切换类,核心是利用DOM的父子嵌套关系而非ID,结合事件绑定控制元素状态:

  • 渲染时为包含子分类的li添加标识类(如has-children),默认隐藏其子ul
  • 为这类li绑定点击事件,通过切换自身的expanded类来控制子ul的显示/隐藏
  • 使用事件阻止冒泡,确保点击子节点不会触发父节点的状态切换

修正后的完整代码

HTML

<div class="funding__categories"></div>

CSS(控制展开/收起样式)

/* 默认隐藏子分类列表 */
.parent {
  display: none;
  margin-left: 1rem;
}

/* 根节点(主分类)默认显示 */
.funding__categories > .parent {
  display: block;
  margin-left: 0;
}

/* 有子分类的项样式 */
.has-children {
  cursor: pointer;
  font-weight: 500;
}

.has-children::before {
  content: "+ ";
  font-size: 0.9em;
  color: #666;
}

/* 展开状态的样式 */
.expanded.has-children::before {
  content: "- ";
}

JavaScript

const menu = [
  {
    id: 1,
    name: "Desserts",
    groups: [
      {
        id: 2,
        name: "Cold",
        groups: [
          { id: 3, name: "Ice Cream", groups: [] },
          { id: 4, name: "Cold brew coffee", groups: [] }
        ]
      },
      {
        id: 5,
        name: "Hot",
        groups: [
          { id: 6, name: "Pancakes", groups: [] },
          { id: 7, name: "Apple pie", groups: [] }
        ]
      }
    ]
  },
  { id: 8, name: "Water", groups: [] },
  {
    id: 7,
    name: "Tea",
    groups: [
      {
        id: 8,
        name: "Green tea",
        groups: [
          { id: 9, name: "With Jasmine", groups: [] },
          { id: 10, name: "Plain", groups: [] }
        ]
      },
      { id: 11, name: "Black Tea", groups: [] }
    ]
  }
];

const menuEl = document.querySelector(".funding__categories");

// 传入整个menu数组,渲染主分类
addElements(menuEl, menu);

function addElements(parent, arr) {
  const ul = document.createElement("ul");
  ul.classList.add("parent");
  parent.appendChild(ul);

  arr.forEach(item => {
    const li = document.createElement("li");
    li.dataset.id = item.id;
    li.textContent = item.name;
    ul.appendChild(li);

    if (item.groups.length > 0) {
      // 标记有子分类的项
      li.classList.add("has-children");
      // 递归渲染子分类
      addElements(li, item.groups);
      // 绑定点击事件切换展开状态
      li.addEventListener("click", (e) => {
        // 阻止事件冒泡,避免父级节点触发切换
        e.stopPropagation();
        li.classList.toggle("expanded");
      });
    }
  });
}

关键说明

  1. 主分类显示修复:将addElements的第二个参数改为menu,直接渲染所有主分类,同时通过CSS让根节点的ul默认显示。
  2. 层级交互控制:
    • 通过has-children类标记可展开项,结合CSS伪元素添加展开/收起图标
    • 点击事件中使用e.stopPropagation()确保每个层级的切换独立,不会影响父节点
    • 完全依赖数组的嵌套结构和DOM父子关系,无需硬编码ID,适配动态数据场景
  3. 类切换问题解决:每个li的类切换仅作用于自身,不会影响其他元素,因为事件绑定在单个li上,且状态切换基于元素自身的类列表。

内容的提问来源于stack exchange,提问作者Marina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 06:36:26