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

Node.js实现SQL Server菜单数据树形结构展示方案问询

扁平菜单转树形结构的实现方法

核心思路

  • 先建立父ID与子节点的映射表,快速定位每个节点的子项
  • 筛选出所有根节点(根据你的AUT_MENU表定义,通常是parentId为0、null或-1的节点)
  • 通过递归或迭代的方式,为每个节点添加children属性,填充对应的子节点

基础递归实现代码

假设你的扁平菜单数据结构如下(字段名可根据实际表结构调整):

// 示例扁平菜单数据
const flatMenus = [
  { id: 1, parentId: 0, name: '系统管理', path: '/system' },
  { id: 2, parentId: 1, name: '用户管理', path: '/system/users' },
  { id: 3, parentId: 1, name: '角色管理', path: '/system/roles' },
  { id: 4, parentId: 0, name: '内容管理', path: '/content' },
  { id: 5, parentId: 4, name: '文章管理', path: '/content/articles' }
];

function buildTree(flatData, parentKey = 'parentId', idKey = 'id', childrenKey = 'children') {
  // 1. 构建父ID到子节点的映射
  const parentMap = {};
  flatData.forEach(item => {
    const parentId = item[parentKey];
    if (!parentMap[parentId]) parentMap[parentId] = [];
    parentMap[parentId].push({ ...item, [childrenKey]: [] });
  });

  // 2. 获取根节点(此处假设parentId=0为根,需根据你的表结构调整)
  const rootNodes = parentMap[0] || [];

  // 3. 递归填充子节点
  function fillChildren(nodes) {
    nodes.forEach(node => {
      const children = parentMap[node[idKey]] || [];
      node[childrenKey] = children;
      fillChildren(children);
    });
  }

  fillChildren(rootNodes);
  return rootNodes;
}

// 使用示例
const treeMenus = buildTree(flatMenus);
console.log(JSON.stringify(treeMenus, null, 2));

大数据量适配:迭代实现(避免递归栈溢出)

如果菜单数据量很大,递归可能导致栈溢出,改用队列迭代的方式更稳妥:

function buildTreeIterative(flatData, parentKey = 'parentId', idKey = 'id', childrenKey = 'children') {
  const parentMap = {};
  const nodeMap = {};

  // 先把所有节点存入映射表,初始化children数组
  flatData.forEach(item => {
    nodeMap[item[idKey]] = { ...item, [childrenKey]: [] };
    const parentId = item[parentKey];
    if (!parentMap[parentId]) parentMap[parentId] = [];
    parentMap[parentId].push(item[idKey]);
  });

  // 获取根节点
  const rootIds = parentMap[0] || [];
  const rootNodes = rootIds.map(id => nodeMap[id]);

  // 用队列迭代填充子节点
  const queue = [...rootNodes];
  while (queue.length > 0) {
    const currentNode = queue.shift();
    const childIds = parentMap[currentNode[idKey]] || [];
    childIds.forEach(id => {
      const childNode = nodeMap[id];
      currentNode[childrenKey].push(childNode);
      queue.push(childNode);
    });
  }

  return rootNodes;
}

实用注意事项

  • 根节点判断:根据AUT_MENU表的实际定义调整,比如有的表用parentId = null或parentId = -1表示根节点,只需修改parentMap[0]对应的键即可
  • 字段适配:如果你的表字段不是id/parentId,比如是menuId/parentMenuId,调用时传入对应参数:buildTree(flatMenus, 'parentMenuId', 'menuId')
  • 调试技巧:转换前可以console.log(parentMap),检查父ID与子节点的映射是否正确建立

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:53:27