用 <select> 做两级联动必须使用两个独立的 <select> 元素,通过 JavaScript 监听一级 change 事件动态更新二级选项;需用 options.length = 0 或循环 removeChild 清空再 appendChild 新 option,避免 innerHTML 导致事件丢失或 XSS 风险,并确保 value 唯一、保留默认提示项。

用 <select> 做两级联动,结构必须分清“控制源”和“受控目标”
纯 HTML 的 <select> 本身不支持嵌套或联动,所谓“两级”,本质是两个独立的 <select> 元素:第一个(如省份)触发变化,第二个(如城市)被 JavaScript 动态重写选项。关键不在样式,而在 DOM 关系是否可预测。
常见错误现象:document.getElementById('city').innerHTML = '<option>北京</option>' 直接覆盖整个 <select>,导致已绑定的 change 事件丢失;或未清空旧选项就追加,造成重复。
- 一级
<select id="province">必须有value唯一标识(如"bj"),不能只靠文本匹配 - 二级
<select id="city">初始状态应含默认提示项:<option value="">请选择城市</option> - 更新二级时,先用
while (citySelect.firstChild) citySelect.removeChild(citySelect.firstChild)清空,再用citySelect.appendChild(optionEl)插入新<option>元素(不用字符串拼接)
三级联动必须拆解为“链式依赖”,不能靠单次事件广播
从“省→市→区”扩展到三级,不是给二级加个 change 监听器就完事。用户选完市之后,区列表才具备上下文;若省还没选、市为空,区菜单应禁用且不可聚焦。
性能影响:如果把全部省市区数据一次性塞进 JS 对象,页面加载变慢;但每次选市都发请求,又增加延迟和失败风险。折中方案是预加载省级数据,市级按需懒加载(首次展开时 fetch),区级缓存市级响应结果。
立即学习“前端免费学习笔记(深入)”;
- 区级
<select id="district">初始化时设disabled属性,并加aria-disabled="true" - 市级
change触发后,仅当event.target.value !== ''才发起区级数据拉取 - 避免在市级
change回调里直接操作districtSelect.innerHTML,改用 DocumentFragment 批量插入,减少重排
DOM 结构错位会导致 CSS 定位失效,hover 或点击区域偏移
多级下拉菜单常配合 position: absolute 实现悬停展开,但一旦父容器用了 transform、perspective 或 will-change,就会创建新的层叠上下文,导致子菜单定位基准错乱——明明写了 top: 100%,却飘到页面左上角。
常见错误现象:二级菜单悬停时闪退、鼠标移向子项途中消失、移动端点击无反应(因 hover 在触摸设备上不触发)。
- 确保所有父级容器没意外设置
overflow: hidden或clip-path,否则子菜单可能被裁剪 - 二级
<ul>必须是对应一级<li>的**直接子元素**,不能靠 JS 插入到 body 底部再用 CSS “飞”过去 - 每个可展开的
<li>必须设position: relative,否则absolute子菜单会向上找最近的position祖先定位
键盘导航不是“锦上添花”,而是可访问性的硬性门槛
仅靠 :hover + CSS 实现的菜单,对键盘用户完全不可用:Tab 进入一级后,按 → 无法进入二级,按 ↓ 也无法在当前级循环聚焦。浏览器不会自动识别这些 <a> 或 <li> 构成一个逻辑菜单组。
容易被忽略的地方:W3C 要求 aria-haspopup 的值必须是 "menu",设成 "true" 是废弃写法;且子菜单容器必须带 role="menu" 和 aria-labelledby,指向触发它的元素 ID。
- 一级触发项(如
<button>或<a>)加aria-haspopup="menu"和aria-expanded="false" - 对应子菜单
<ul>加role="menu"和aria-labelledby="trigger-id" - 每个菜单项用
role="menuitem",禁用项加aria-disabled="true"并设tabindex="-1"
position: relative 漏设、父容器 transform 干扰、或 padding 不足三个地方同时排查。



















