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

如何用JS处理嵌套对象数组实现层级选择菜单功能?

层级分类选择菜单实现步骤

一、搭建基础HTML结构

先写出核心DOM结构,包含触发按钮、弹出层、已选列表:

<button id="openMenuBtn">选择分类</button>
<!-- 弹出层 -->
<div id="categoryModal" class="modal hidden">
  <div class="modal-header">
    <button id="backBtn" class="hidden">← 返回上一级</button>
    <span>选择分类</span>
  </div>
  <div id="categoryList" class="category-list"></div>
</div>
<!-- 已选列表 -->
<div class="selected-container">
  <h3>已选分类</h3>
  <ul id="selectedList"></ul>
</div>

二、JavaScript核心逻辑实现

1. 定义状态变量

声明需要跟踪的核心状态,放在全局或模块作用域:

const menu = [{ categories: [{ id: 1, name: 'Desserts', categories: [{ id: 2, name: 'Ice cream', categories: [{ id: 3, name: 'Vanilla', categories: [] }, { id: 4, name: 'Strawberry', categories: [] }] }, { id: 5, name: 'Baked apples', categories: [] }] }, { id: 6, name: 'Coffee', categories: [] }, { id: 7, name: 'Tea', categories: [{ id: 8, name: 'Green tea', categories: [{ id: 9, name: 'With Jasmine', categories: [] }, { id: 10, name: 'Simple', categories: [] }] }, { id: 11, name: 'Black Tea', categories: [] }] }] }];

// 状态变量
let currentLevel = menu[0].categories; // 当前展示的层级数据
let levelHistory = []; // 层级历史,用于返回上一级
let selectedCategories = []; // 已选分类列表

// DOM元素引用
const openBtn = document.getElementById('openMenuBtn');
const modal = document.getElementById('categoryModal');
const backBtn = document.getElementById('backBtn');
const categoryList = document.getElementById('categoryList');
const selectedList = document.getElementById('selectedList');

2. 绑定基础交互事件

给触发按钮、返回按钮绑定点击逻辑:

// 打开弹出层
openBtn.addEventListener('click', () => {
  modal.classList.remove('hidden');
  renderCategoryList(currentLevel);
  updateBackBtnStatus();
});

// 返回上一级
backBtn.addEventListener('click', () => {
  if (levelHistory.length === 0) return;
  currentLevel = levelHistory.pop();
  renderCategoryList(currentLevel);
  updateBackBtnStatus();
});

3. 渲染当前层级分类选项

编写函数根据当前层级数据生成可点击的选项:

function renderCategoryList(data) {
  categoryList.innerHTML = ''; // 清空当前列表
  data.forEach(item => {
    const li = document.createElement('li');
    li.className = 'category-item';
    li.textContent = item.name;
    // 绑定点击事件
    li.addEventListener('click', () => {
      if (item.categories.length > 0) {
        // 有子分类,进入下一级
        levelHistory.push(currentLevel);
        currentLevel = item.categories;
        renderCategoryList(currentLevel);
        updateBackBtnStatus();
      } else {
        // 无子分类,加入已选列表
        selectedCategories.push({ id: item.id, name: item.name });
        renderSelectedList();
        modal.classList.add('hidden'); // 可选:选完关闭弹出层
      }
    });
    categoryList.appendChild(li);
  });
}

4. 控制返回按钮显示状态

根据层级历史判断是否显示返回按钮:

function updateBackBtnStatus() {
  backBtn.classList.toggle('hidden', levelHistory.length === 0);
}

5. 渲染已选列表(支持删除)

编写函数生成已选列表,并实现删除功能:

function renderSelectedList() {
  selectedList.innerHTML = '';
  if (selectedCategories.length === 0) {
    const emptyLi = document.createElement('li');
    emptyLi.textContent = '暂无选择';
    selectedList.appendChild(emptyLi);
    return;
  }
  selectedCategories.forEach((item, index) => {
    const li = document.createElement('li');
    li.innerHTML = `${item.name} <button class="del-btn" data-index="${index}">删除</button>`;
    // 删除按钮事件
    li.querySelector('.del-btn').addEventListener('click', (e) => {
      const idx = e.target.dataset.index;
      selectedCategories.splice(idx, 1);
      renderSelectedList();
    });
    selectedList.appendChild(li);
  });
}

三、关键CSS样式参考

基于你的HTML/CSS能力,给出核心样式方向,细节可自行调整:

/* 弹出层基础样式 */
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 1px solid #ccc;
  padding: 16px;
  background: white;
  z-index: 1000;
}
/* 隐藏类 */
.hidden {
  display: none;
}
/* 分类列表样式 */
.category-list {
  list-style: none;
  padding: 0;
  margin: 16px 0;
}
.category-item {
  padding: 8px;
  cursor: pointer;
  border-radius: 4px;
}
.category-item:hover {
  background-color: #f5f5f5;
}
/* 已选列表样式 */
.selected-container {
  margin-top: 20px;
}
.del-btn {
  margin-left: 8px;
  padding: 2px 6px;
  cursor: pointer;
}

四、测试与边界处理

  • 验证返回按钮:处于最顶层时,返回按钮自动隐藏
  • 验证末级分类:点击后正确加入已选列表,弹出层正常关闭
  • 验证删除功能:删除已选项后列表实时更新
  • 可选优化:若需支持选择中间层级(如直接选「Desserts」而非末级),可给每个选项添加「选择当前分类」的独立按钮,或修改点击逻辑增加选择判断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 00:57:22