如何动态生成带可折叠ul/li标签的多列树形列表
可折叠树列表复选框独立列布局方案
问题核心
当前手写的可折叠树列表采用默认流式排版,复选框直接跟在名称后,没有做列分区,既无法对齐,也不方便后续扩展物料规格、数量等更多字段。
基于现有代码的改造方案
改造总思路是给每个列表行加弹性布局,拆分独立列容器,所有层级的列宽保持统一,同时修复点击复选框误触发折叠的问题。
1. 修改节点渲染函数
拆分列表项内容为独立列元素,预留后续扩展列的位置,给复选框加事件阻止冒泡:
function check(obj) { let html = ''; const name = obj.name ? `${obj.name} (${obj.type})` : obj.type; html += '<div class="node">' html += '<li class="ntitle">'; // 名称列:放折叠图标+部件名称 html += ' <span class="col name-col">'; html += ' <span class="expand-icon"></span>'; html += name; html += ' </span>'; // 复选框列:固定宽度,阻止点击冒泡 html += ' <span class="col check-col">'; html += ` <input type="checkbox" name="${obj.id-id}" value="checked" onchange="snap(this)" onclick="event.stopPropagation()"/>`; html += ' </span>'; // 后续新增列直接在此处追加即可,示例: // html += ` <span class="col spec-col">${obj.spec || '-'}</span>`; // html += ` <span class="col qty-col">${obj.qty || 0}</span>`; html += '</li>'; if (obj.children?.length) { html += '<ul class="children hide">'; obj.children.forEach(child => html += check(child)); html += '</ul>'; } html += "</div>"; return html; }
2. 补充CSS布局样式
用Flex实现多列对齐,统一所有层级的缩进和列宽,折叠图标用内置SVG不用额外图片资源:
.objtree * { box-sizing: border-box; margin: 0; padding: 0; } /* 列表行弹性布局 */ .ntitle { list-style: none; display: flex; align-items: center; min-height: 36px; cursor: pointer; border-bottom: 1px solid #eee; } /* 通用列样式 */ .col { padding: 0 8px; } /* 名称列自适应宽度 */ .name-col { flex: 1; display: flex; align-items: center; } /* 复选框列固定宽度,全局对齐 */ .check-col { width: 60px; text-align: center; } /* 折叠展开图标 */ .expand-icon { width: 16px; height: 16px; margin-right: 6px; flex-shrink: 0; background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg>') center/contain no-repeat; transition: transform .2s ease; } /* 展开状态图标旋转90度 */ .ntitle.open .expand-icon { transform: rotate(90deg); } /* 子列表缩进,和父级名称对齐 */ .children { padding-left: 26px; } .children.hide { display: none; } /* 无子节点的项保留图标占位,保证列对齐 */ .node:not(:has(.children)) .expand-icon { visibility: hidden; }
3. 优化事件绑定逻辑
改用事件委托,动态渲染的节点不需要重复绑定事件:
function assignEvent() { $('.objtree') .off('click', '.ntitle') .on('click', '.ntitle', function () { const $childList = $(this).parent().find('.children:first'); $(this).toggleClass('open'); $childList.toggleClass('hide'); }) }
更优的长期方案
如果后续树结构层级更深、列数更多,或者需要支持搜索、筛选、节点拖拽等能力,不建议继续维护手写列表,直接用成熟的**树形表格(TreeGrid)**组件即可:
- 主流UI库(Ant Design、Element UI、Layui等)都自带开箱即用的树形表格组件,原生支持多列对齐、复选框选择、固定列、自定义单元格模板
- 组件内部已经处理好了缩进对齐、事件冒泡、性能优化等问题,不需要手动维护布局逻辑,扩展性远强于手写的列表结构
效果参考
- 现有效果

- 目标效果

内容的提问来源于stack exchange,提问作者Jeff Boker
相关产品推荐
相关产品推荐

