用不到50行原生js实现高性能级联选择器,核心是事件委托+扁平数据映射:通过data-level/data-parent标记层级关系,用key-value结构o(1)查下级选项,单次change委托动态填充下一级select,支持动态插入、自动初始化与深层清空。

用不到 50 行原生 JS 实现高性能企业级级联选择器,关键不在“写全功能”,而在“精准控制数据流 + 委托驱动视图更新”。核心思路是:父级 select 变化时,不重绘整个 DOM,只动态生成下一级 options,并通过事件委托统一处理所有 select 的 change 事件——这样既支持动态插入行、又避免为每个 select 单独绑定监听器。
一、结构设计:用 data-level 和 data-parent 标记层级关系
HTML 中所有 select 都带两个自定义属性:
- data-level="1":标识当前是第几级(如省→市→区)
- data-parent="province":标识它依赖哪个上级字段的 value(用于查表)
示例片段:
<select data-level="1" name="province"><option>请选择省份</option></select><br><select data-level="2" data-parent="province" name="city"></select><br><select data-level="3" data-parent="city" name="district"></select>
二、数据预置:用扁平对象模拟树形结构
不用嵌套 JSON,改用 key-value 映射,提升查找速度:
const cascadeData = {<br> // 省份列表<br> 'province': ['北京', '上海', '广东'],<br> // 城市:key 是上级值,value 是本级可选项<br> 'Beijing': ['朝阳区', '海淀区', '丰台区'],<br> 'Shanghai': ['浦东新区', '徐汇区', '静安区'],<br> 'Guangdong': ['广州', '深圳', '珠海']<br>};
这样根据 e.target.value 直接查 cascadeData[value],O(1) 时间完成下拉填充。
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
三、事件委托:单次绑定,覆盖全部 select
只在 body 或容器上监听一次 change,用 matches 过滤目标:
document.body.addEventListener('change', e => {<br> if (!e.target.matches('select[data-level]')) return;<br> const level = +e.target.dataset.level;<br> const nextLevel = level + 1;<br> const nextSelect = document.querySelector(`select[data-level="${nextLevel}"][data-parent="${e.target.name}"]`);<br> if (!nextSelect) return;<br> // 清空并填充下一级<br> nextSelect.innerHTML = '<option>请选择</option>';<br> const options = cascadeData[e.target.value] || [];<br> options.forEach(text => {<br> const opt = document.createElement('option');<br> opt.value = text;<br> opt.textContent = text;<br> nextSelect.appendChild(opt);<br> });<br>});
这段代码约 25 行,已支撑三级联动。如需清空更深层级,加个循环即可,总行数仍可控。
四、增强细节:防重复、保状态、兼容动态插入
实际业务中还需三点补充(共约 15 行):
- change 前先清空所有下级 select(从当前 level+1 开始)
- 给每个 select 添加 data-init="true" 标识是否已初始化,避免首次加载时误触发
- 若新行是 JS 动态插入的,无需重新绑定——委托天然生效
最后补一行初始化逻辑:document.querySelectorAll('select[data-level="1"]').forEach(s => s.dispatchEvent(new Event("change"))),自动展开首级。
整套方案不依赖任何库,无虚拟 DOM,DOM 操作极简,45 行内落地,兼顾可维护性与运行效率。










