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

React.js:如何从嵌套JSON动态创建DOM并渲染层级文档树菜单

我之前刚好处理过类似的嵌套JSON渲染层级文档树菜单的需求,根据不同的技术栈,分享几个实用的实现方案:

核心思路

你的JSON数据是典型的嵌套层级结构,每个节点包含title(显示文本)、path(跳转路径)、children(子节点数组)。核心逻辑就是递归遍历每个节点,根据节点是否有子节点来生成对应的层级DOM结构/组件。


方案1:原生JavaScript实现(无框架)

适合不需要前端框架的简单场景,直接用DOM操作生成菜单:

HTML结构

<div id="menu-container"></div>

JavaScript代码

// 修正了原数据里的路径错误(Ooty carrot的path对应Carrot而非Brinjal)
const menuData = [
  { 
    "title": "Food", 
    "path": "/root", 
    "children": [
      { 
        "title": "Veg", 
        "path": "/root/Food", 
        "children": [
          { 
            "title": "Carrot", 
            "path": "/root/Food/Veg", 
            "children": [
              { 
                "title": "Ooty carrot", 
                "path": "/root/Food/Veg/Carrot", 
                "children": [] 
              }
            ] 
          }
        ] 
      }
    ] 
  }, 
  { 
    "title": "Cloths", 
    "path": "/root", 
    "children": [
      { 
        "title": "T shirt", 
        "path": "/root/Cloths/Tshirt", 
        "children": [] 
      }
    ] 
  }
];

// 递归生成菜单节点
function generateMenuNodes(data) {
  const ul = document.createElement('ul');
  
  data.forEach(node => {
    const li = document.createElement('li');
    // 创建跳转链接
    const link = document.createElement('a');
    link.href = node.path;
    link.textContent = node.title;
    li.appendChild(link);
    
    // 如果存在子节点,递归生成子菜单
    if (node.children?.length) {
      li.appendChild(generateMenuNodes(node.children));
    }
    
    ul.appendChild(li);
  });
  
  return ul;
}

// 将菜单挂载到页面容器
const container = document.getElementById('menu-container');
container.appendChild(generateMenuNodes(menuData));

方案2:React 组件实现

如果你的项目用React,可以拆分为递归组件来实现:

import React from 'react';

// 单个菜单项组件,递归渲染子节点
const MenuItem = ({ node }) => {
  return (
    <li>
      <a href={node.path}>{node.title}</a>
      {/* 存在子节点时渲染子菜单 */}
      {node.children?.length && (
        <ul>
          {node.children.map((child, idx) => (
            <MenuItem key={idx} node={child} />
          ))}
        </ul>
      )}
    </li>
  );
};

// 菜单根组件
const DocumentTreeMenu = ({ data }) => {
  return (
    <ul>
      {data.map((node, idx) => (
        <MenuItem key={idx} node={node} />
      ))}
    </ul>
  );
};

// 使用示例:在父组件中引入并传递数据
// <DocumentTreeMenu data={menuData} />

方案3:Vue 组件实现

Vue中可以利用递归组件的特性,实现起来非常简洁:

<template>
  <ul>
    <li v-for="(node, idx) in data" :key="idx">
      <a :href="node.path">{{ node.title }}</a>
      <!-- 递归调用自身组件渲染子菜单 -->
      <menu-tree v-if="node.children?.length" :data="node.children" />
    </li>
  </ul>
</template>

<script>
export default {
  name: 'MenuTree', // 必须定义name才能递归调用
  props: {
    data: {
      type: Array,
      required: true
    }
  }
};
</script>

<!-- 使用示例:在父组件中引入 -->
<!-- <MenuTree :data="menuData" /> -->

额外优化建议

  1. 唯一Key的使用:示例中用了idx作为key,实际项目建议用节点的唯一标识(比如新增id字段),避免列表更新时的渲染错误。
  2. 折叠展开功能:可以给有子节点的菜单添加折叠按钮,通过状态控制子菜单的显示/隐藏,提升交互体验。
  3. 样式美化:给不同层级的菜单添加缩进(比如padding-left: 1.5rem)、图标等,让层级更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:13:58