原生html+javascript实现省→市两级级联下拉,须用select标签配合change事件监听,每次切换前清空并重写第二级innerhtml,采用provincecode外键式json结构映射城市数据,并同步重置value、selectedindex及aria-disabled确保状态干净。

用原生 HTML + JavaScript 实现两级级联下拉(省→市)
纯 HTML 的 <input> 标签本身不支持级联逻辑,必须配合 <select></select> 和 JavaScript 才能响应式联动。常见错误是试图只用 disabled 或 hidden 属性静态控制第二级,结果数据没清空、选项残留、提交时出错。
核心做法:监听第一级 <select></select> 的 change 事件,动态重写第二级 <select></select> 的 innerHTML 或逐个 appendChild option 元素。
- 第一级选“北京”,第二级应只出现“朝阳区”“海淀区”等,不能保留上一次“广州市”的选项
- 每次切换前必须先清空第二级的全部
<option></option>,否则会叠加 - 推荐用
selectEl.innerHTML = ''清空,比循环removeChild更简洁 - 若城市数据量大(>200 条),考虑用
document.createDocumentFragment()批量插入,避免频繁重排
JSON 数据结构怎么组织才方便前端映射
后端返回扁平数组或嵌套对象都行,但前端处理成本差异大。最易维护的是「外键式」结构:省级列表独立,市级列表按 provinceCode 分组。
const provinces = [
{ code: 'bj', name: '北京市' },
{ code: 'gd', name: '广东省' }
];
const cities = {
'bj': [{ name: '朝阳区' }, { name: '海淀区' }],
'gd': [{ name: '广州市' }, { name: '深圳市' }]
};
这样 cities[select1.value] 就能直接取到对应城市数组,不用遍历查找。避免把所有省市区塞进一个大数组再用 filter() 筛选——既慢又容易漏掉空数组判断。
- 如果后端给的是扁平数组(如
[{province:'北京',city:'朝阳'}]),前端首次加载时就该预处理成上面的cities对象 -
provinceCode建议用短字符串(如'bj'),别用中文名作 key,避免空格、全角字符导致匹配失败 - 务必加空值校验:
if (!cities[selectedCode]) { secondSelect.innerHTML = '<option value="">请选择城市</option>'; return; }
为什么不能只靠 CSS 隐藏第二级 select 而不重置 value
仅用 style.display = 'none' 或 hidden 属性隐藏第二级下拉框,但不重置其 value 和 selectedIndex,会导致两个问题:
- 表单提交时,被隐藏的
<select></select>若有name属性,它的value仍会被发送(浏览器行为) - 用户切回第一级后,第二级可能还显示着上次选中的值,但实际选项已变,造成视觉与数据不一致
- 更隐蔽的问题:某些校验库(如 jQuery Validation)会检查
:visible元素,但忽略hidden属性,导致误判必填项
正确做法是:隐藏同时执行 secondSelect.value = '' 和 secondSelect.selectedIndex = -1,确保状态干净。
移动端 Safari 下 change 事件触发时机异常怎么办
在 iOS Safari 中,change 事件有时不会在用户点选后立即触发,尤其当页面有滚动或快速切换时。这不是 bug,而是 Safari 对表单控件的优化策略——它可能延迟触发以等待用户确认。
稳妥方案是同时监听 input 和 change 事件,或改用 blur 作为兜底:
firstSelect.addEventListener('change', updateCities);
firstSelect.addEventListener('input', updateCities); // iOS Safari 支持 input 事件
// 或者:
firstSelect.addEventListener('blur', () => {
if (firstSelect.matches(':focus')) return;
updateCities();
});
注意不要只依赖 input,因为部分安卓 WebView 不触发它;也不要只依赖 blur,因为用户可能还没松手就失焦。双保险更可靠。
级联的关键不在样式多炫,而在每次选择后,第二级的 DOM、value、selectedIndex、可访问性属性(aria-disabled)是否同步归零并重建。漏掉任意一环,后续交互就会开始漂移。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











