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

如何实现文件夹优先排序的层级嵌套UL列表?

问题描述

从层级分类数组生成嵌套UL列表,子分类关联父分类ID,要求展示规则为:有子项的“文件夹”类列表项排在前面,无子项的“文件”类列表项在后。当前实现会按数组顺序生成列表(实际表现为字母排序),不符合需求,例如data-id=7的catA_2被夹在两个文件夹UL之间,而非排在所有文件夹之后。

期望的HTML结构
<ul id='myList' class="folder">
  <li data-id=0>
    <ul class="folder">
      <li data-id=1>catA
        <ul class="folder">
          <li data-id=3>catA_1
          <ul>
            <li data-id=4>catA_1_1</li>
          </ul> 
          <ul>
            <li data-id=5>catA_1_2</li>
          </ul> 
          <ul>
            <li data-id=6>catA_1_3</li>
          </ul>                              
          </li>
        </ul>
        <ul class="folder">
          <li data-id=8>catA_3
            <ul>
              <li data-id=9>catA_3_1</li>
            </ul>
            <ul>
              <li data-id=10>catA_3_2</li>
            </ul>
            <ul class="folder">
              <li data-id=11>catA_3_3
                <ul>
                  <li data-id=12>catA_3_3_1</li>
                </ul>
                <ul><li data-id=13>catA_3_3_2</li></ul>
              </li>
            </ul>
          </li>
        </ul>
        <ul>
          <li data-id=7>catA_2</li>  <!-- 这两项(data-id=7 & 14)排在文件夹之后,因为它们没有子项 -->
        </ul>
        <ul>
          <li data-id=14>catA_4</li>
        </ul>               
      </li>
    </ul>
    <ul>
      <li data-id=2>catB</li> <!-- catB同理 -->
    </ul>    
  </li>
</ul>
当前实现代码

JavaScript

const src = [[1,"catA",0],[2,"catB",0],[3,"catA_1",1],[4,"catA_1_1",3],[5,"catA_1_2",3],[6,"catA_1_3",3],[7,"catA_2",1],[8,"catA_3",1],[9,"catA_3_1",8],[10,"catA_3_2",8],[11,"catA_3_3",8],[12,"catA_3_3_1",11],[13,"catA_3_3_2",11],[14,"catA_4",1],[15,"catB_1",2],[16,"catB_1_1",15],[17,"catB_1_2",16],[18,"catB_1_3",16],[19,"catB_2",15],[20,"catB_3",15],[21,"catB_3_1",20],[22,"catB_3_2",20],[23,"catB_3_3",20],[24,"catB_3_3_1",23],[25,"catB_3_3_2",23],[26,"catB_4",15]];

function tree(src, parent = 0) {
  const el = document.getElementById("myList").querySelector("li[data-id='" + parent + "']");
  
  if (!el) return;
  
  for (var i = 0; i < src.length; i++) {
    if (src[i][2] === parent) {
      const new_parent = src[i][0];
      el.insertAdjacentHTML("beforeend", "<ul><li data-id='" + new_parent + "'>" + src[i][1] + "</li></ul>");
      el.parentElement.classList.add("folder");
      tree(src, new_parent);
    }
  }
}

tree(src)

HTML

<ul id='myList'>
  <li data-id=0></li>
</ul>
解决方案

核心思路是先筛选并处理有子项的分类(文件夹),再处理无子项的分类(文件),具体实现如下:

  1. 提前建立父ID到子分类的映射,快速判断某个分类是否有子项;
  2. 在递归函数中拆分当前父分类的子项为两组,优先处理文件夹类项,再处理文件类项。

修改后的JavaScript代码:

const src = [[1,"catA",0],[2,"catB",0],[3,"catA_1",1],[4,"catA_1_1",3],[5,"catA_1_2",3],[6,"catA_1_3",3],[7,"catA_2",1],[8,"catA_3",1],[9,"catA_3_1",8],[10,"catA_3_2",8],[11,"catA_3_3",8],[12,"catA_3_3_1",11],[13,"catA_3_3_2",11],[14,"catA_4",1],[15,"catB_1",2],[16,"catB_1_1",15],[17,"catB_1_2",16],[18,"catB_1_3",16],[19,"catB_2",15],[20,"catB_3",15],[21,"catB_3_1",20],[22,"catB_3_2",20],[23,"catB_3_3",20],[24,"catB_3_3_1",23],[25,"catB_3_3_2",23],[26,"catB_4",15]];

// 建立父ID到子分类的映射,用于快速判断是否有子项
const parentMap = src.reduce((map, item) => {
  const parentId = item[2];
  if (!map[parentId]) map[parentId] = [];
  map[parentId].push(item);
  return map;
}, {});

// 判断某个分类是否有子项
function hasChildren(id) {
  return parentMap[id] && parentMap[id].length > 0;
}

function tree(src, parent = 0) {
  const el = document.getElementById("myList").querySelector("li[data-id='" + parent + "']");
  
  if (!el) return;

  // 获取当前父分类下的所有子项
  const children = parentMap[parent] || [];
  // 分成两组:有子项的(文件夹)和无子项的(文件)
  const folderItems = children.filter(item => hasChildren(item[0]));
  const fileItems = children.filter(item => !hasChildren(item[0]));

  // 先处理文件夹
  folderItems.forEach(item => {
    const new_parent = item[0];
    const ul = document.createElement('ul');
    ul.classList.add('folder');
    ul.innerHTML = `<li data-id='${new_parent}'>${item[1]}</li>`;
    el.appendChild(ul);
    el.parentElement.classList.add("folder");
    tree(src, new_parent);
  });

  // 再处理文件
  fileItems.forEach(item => {
    const new_parent = item[0];
    const ul = document.createElement('ul');
    ul.innerHTML = `<li data-id='${new_parent}'>${item[1]}</li>`;
    el.appendChild(ul);
  });
}

tree(src)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:38:13