大家在浏览网页时,有没有遇到过下面这样的多级筛选框
有没有想过,这里的逻辑判断是如何完成的?接下来,楼主就带领大家利用原生JS语法来完成这样一个多级筛选框,有路过的小伙伴记得留个赞哟!!!!
第一步,咱们先创建一个基础的HTML页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>地址多级下拉筛选框</title>
</head>
<body>
</body>
</html>
第二步,咱们给HTML页面添加三个表单下拉框,放入body里。
<form action="">
<select name="province">
<option value="" >--省--</option>
</select>
<select name="city">
<option value="" >--市--</option>
</select>
<select name="county">
<option value="" >--区/县--</option>
</select>
<button type="reset">重置</button>
</form>
第三步,给页面加点样式,让这个下拉框居中显示。
<style>
body {
padding-top: 50px;
text-align: center;
}
</style>
此时一个酷炫的三级筛选框就出现啦!!!
当然,这是一个没有灵魂,无法和用户交互的筛选框,当我们点击时,并不会有任何东西出现。
接下来,我就给他注入灵魂,让它能跟随我们的选择来显示不同的内容。
第四步,创建一个script标签,并放入我们需要的数据,当然,因为全国城市太多,楼主这里就只选择了两个省和他们的前两个市及前两个区县,有兴趣的小伙伴可以对照地图将数据补全哈!
<script>
const obj = {
"河北省": {
"石家庄市": {
"长安区": {},
"桥西区": {},
"新华区": {},
"井陉矿区": {},
"裕华区": {},
"藁城区": {},
"鹿泉区": {},
"栾城区": {},
"井陉县": {},
"正定县": {},
"行唐县": {},
"灵寿县": {},
"高邑县": {},
"深泽县": {},
"赞皇县": {},
"无极县": {},
"平山县": {},
"元氏县": {},
"赵县": {},
"辛集市": {},
"晋州市": {},
"新乐市": {},
},
"唐山市": {
"路南区": {},
"路北区": {},
"古冶区": {},
"开平区": {},
"丰南区": {},
"丰润区": {},
"曹妃甸区": {},
"滦县": {},
"滦南县": {},
"乐亭县": {},
"迁西县": {},
"玉田县": {},
"遵化市": {},
"迁安市": {},
},
"秦皇岛市": {},
"邯郸市": {},
"邢台市": {},
"保定市": {},
"张家口市": {},
"承德市": {},
"沧州市": {},
"廊坊市": {},
"衡水市": {},
},
"山西省": {
"太原市": {
"小店区": {},
"迎泽区": {},
"杏花岭区": {},
"尖草坪区": {},
"万柏林区": {},
"晋源区": {},
"清徐县": {},
"阳曲县": {},
"娄烦县": {},
"古交市": {},
},
"大同市": {
"新荣区": {},
"平城区": {},
"云冈区": {},
"云州区": {},
"阳高县": {},
"天镇县": {},
"广灵县": {},
"灵丘县": {},
"浑源县": {},
"左云县": {},
},
"阳泉市": {},
"长治市": {},
"晋城市": {},
"朔州市": {},
"晋中市": {},
"运城市": {},
"忻州市": {},
"临汾市": {},
"吕梁市": {},
},
"北京市": {},
"天津市": {},
"内蒙古自治区": {},
"辽宁省": {},
"吉林省": {},
"黑龙江省": {},
"上海市": {},
"江苏省": {},
"浙江省": {},
"安徽省": {},
"福建省": {},
"江西省": {},
"山东省": {},
"河南省": {},
"湖北省": {},
"湖南省": {},
"广东省": {},
"广西壮族自治区": {},
"海南省": {},
"重庆市": {},
"四川省": {},
"贵州省": {},
"云南省": {},
"西藏自治区": {},
"陕西省": {},
"甘肃省": {},
"青海省": {},
"宁夏回族自治区": {},
"新疆维吾尔自治区": {},
"台湾省": {},
"香港特别行政区": {},
"澳门特别行政区": {},
}
</script>
第五步,咱们正式开始Javascript的逻辑部分,首先,在页面已进入,就应该加载出每个省的数据,供用户进行选择。那么就需要我们对上面对象进行遍历,取出obj对象的每一个属性名。
因为对象遍历的方法比较少,所以这里推荐使用Object.key()这个方法取出对象的所有属性值,这个方法会返回给我们一个数组,我们就可以直接对这个数组进行遍历。当然,如果说你非要直接遍历对象的话,也不是不可以,使用 for (Key in obj)就能够遍历对象,这里楼主采用第一种方法。每遍历一个数据我们就生成一个下拉框option。
渲染数据也有两种方式,第一种是dom树驱动,就是每遍历一次,就创建并往dom树中追加一个标签。第二种是数据驱动,创建一个空数组,每循环一次,就创建一个标签存入数组里,等遍历结束后,再一次性追加入dom树中,第二中方法因为对dom树操作次数少,可以提高页面加载速度及性能,所以这里选择第二种。 map()方法会自动创建并返回一个数组来存放我们遍历产生的新数组,所以这里使用map()方法来遍历数组,就不需要我们在去创建空数组了,只用我们定义一个常量来接收这个数组再把它加载进dom树里即可。
当然,我们不能直接把数组加载进,还需要join一下,将数组变成字符串才行。PS这里采用+=赋值是为了避免覆盖默认的下拉框,如果直接采用=赋值,那么页面一打开就会自动加载第一个省,用户体验会很差。当然,后面加载市、县的时候就可以直接赋值,当用户选择省后,市自动变为第一个数据,提醒用户可以选择市了。
综上所述:
// 1加载省数据
const province = Object.keys(obj).map((item) => `<option value="${item}">${item}</option>`)
document.querySelector(`[name='province']`).innerHTML += province.join(``)
此时,页面一加载,我们便可以点击省这个下拉框来选择了。
第六步,我们就需要根据用户选择的省来加载对应的市了。这里,需要用到事件监听,监听用户改变省下拉框的事件,当change这个事件触发时,我们就立即获取用户选择的省,并立即遍历加载对应的市,综上:
// 2加载市,监听省change事件
document.querySelector(`[name='province']`).addEventListener('change', function () {
// 2-1获取当前选择的省,这里的this指向函数的调用者[name='province']这个标签
const province = this.value
const city = Object.keys(obj[province]).map((item) =>`<option value="${item}">${item}</option>`)
document.querySelector(`[name='city']`).innerHTML = city.join(``)
})
同理,加载区县也是在监听到市区发生变化,就立即获取数据渲染
// 3加载县
document.querySelector(`[name='city']`).addEventListener('change', function () {
// 3-1获取当前选择的市
const city = this.value
3-2获取当前选择的省
const province = document.querySelector(`[name='province']`).value
// 3-2加载县
const county = Object.keys(obj[province][city]).map((item) =>`<option value="${item}">${item}</option>`)
document.querySelector(`[name='county']`).innerHTML = county.join(``)
})
那么,写到这里,其实一个简单的小联动效果其实已经可以出来了
但是!但是!但是!这也仅仅完成了基本的需求,因为但凡你多操作几步,你就会发现一堆bug在等着你,比如:
当然,咱们不能干那种自己拉屎别人擦屁股的事对吧?会出现这种情况是因为我们漏了几个逻辑判断。当用户选择完后面市、区县的筛选框再反过来点击省时,将省改为默认的空状态时,我们要强制将后面的市、区也重置成默认状态,如何完成?我们只需在每次事件一触发,立即清空后面市、县的数据即可,我们将加载市、县的事件监听里加两行代码:
// 2加载市,监听省change事件
document.querySelector(`[name='province']`).addEventListener('change', function () {
// 2-1获取当前选择的省
const province = this.value
//以下新增
// 2-2任何时刻,当用户点击省时,立即强制市、县为空
document.querySelector(`[name='city']`).innerHTML = `<option value="">--市--</option>`
document.querySelector(`[name='county']`).innerHTML = `<option value="">--区/县--</option>`
//以上新增
const city = Object.keys(obj[province]).map((item) =>
`<option value="${item}">${item}</option>`)
document.querySelector(`[name='city']`).innerHTML = city.join(``)
})
// 3加载县
document.querySelector(`[name='city']`).addEventListener('change', function () {
// 3-1获取当前选择的市
const city = this.value
//以下新增
// 3-2任何时刻,当用户点击市时,立即强制县为空
document.querySelector(`[name='county']`).innerHTML = `<option value="">--区/县--</option>`
//以上新增
const province = document.querySelector(`[name='province']`).value
// 3-3加载县
const county = Object.keys(obj[province][city]).map((item) =>
`<option value="${item}">${item}</option>`)
document.querySelector(`[name='county']`).innerHTML = county.join(``)
})
以上,即可解决点击省,后面的市、区不重置的问题,如图
最后,还有最后一个bug,就是我们一直忽略的那个button重置按钮,这个表单按钮自带重置属性,但是无法满足我们的需求,需要我们再给它添加一点事件,如图:
市和县重置后显示有文字是因为我们在渲染时使用了=赋值覆盖了数据,将默认数据覆盖掉了,所以,默认数据显示第一个,当然就算将=号换成+=,也一样会有bug,如:
正常我们重置表单后,在未点击省的时候,市和县应该是没有选项才对,但是这里却有显示选项,这是因为数据在我们最开始依次点击时,已经加载了进去,而表单的重置按钮,只会把选项切换到默认选项(就是带有selected属性的标签,如果都没带这个属性,那就显示第一个),而不是删除下拉选项列表,但是我们这里需要删除下拉列表,所以,我们只能手动重置一下了:
document.querySelector(`button`).addEventListener('click',function(){
document.querySelector(`[name='city']`).innerHTML = `<option value="">--市--</option>`
document.querySelector(`[name='county']`).innerHTML = `<option value="">--区/县--</option>`
document.querySelector(`[name='county']`).innerHTML = `<option value="">--区/县--</option>`
})
效果如下,这个简单的小demo就完成了!!!
下面附上完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>省、市、区联动</title>
<style>
body {
padding-top: 50px;
text-align: center;
}
</style>
</head>
<body>
<form action="">
<select name="province">
<option value="" >--省--</option>
</select>
<select name="city">
<option value="">--市--</option>
</select>
<select name="county">
<option value="">--区/县--</option>
</select>
<button type="reset">重置</button>
</form>
<script>
const obj = {
"河北省": {
"石家庄市": {
"长安区": {},
"桥西区": {},
"新华区": {},
"井陉矿区": {},
"裕华区": {},
"藁城区": {},
"鹿泉区": {},
"栾城区": {},
"井陉县": {},
"正定县": {},
"行唐县": {},
"灵寿县": {},
"高邑县": {},
"深泽县": {},
"赞皇县": {},
"无极县": {},
"平山县": {},
"元氏县": {},
"赵县": {},
"辛集市": {},
"晋州市": {},
"新乐市": {},
},
"唐山市": {
"路南区": {},
"路北区": {},
"古冶区": {},
"开平区": {},
"丰南区": {},
"丰润区": {},
"曹妃甸区": {},
"滦县": {},
"滦南县": {},
"乐亭县": {},
"迁西县": {},
"玉田县": {},
"遵化市": {},
"迁安市": {},
},
"秦皇岛市": {},
"邯郸市": {},
"邢台市": {},
"保定市": {},
"张家口市": {},
"承德市": {},
"沧州市": {},
"廊坊市": {},
"衡水市": {},
},
"山西省": {
"太原市": {
"小店区": {},
"迎泽区": {},
"杏花岭区": {},
"尖草坪区": {},
"万柏林区": {},
"晋源区": {},
"清徐县": {},
"阳曲县": {},
"娄烦县": {},
"古交市": {},
},
"大同市": {
"新荣区": {},
"平城区": {},
"云冈区": {},
"云州区": {},
"阳高县": {},
"天镇县": {},
"广灵县": {},
"灵丘县": {},
"浑源县": {},
"左云县": {},
},
"阳泉市": {},
"长治市": {},
"晋城市": {},
"朔州市": {},
"晋中市": {},
"运城市": {},
"忻州市": {},
"临汾市": {},
"吕梁市": {},
},
"北京市": {},
"天津市": {},
"内蒙古自治区": {},
"辽宁省": {},
"吉林省": {},
"黑龙江省": {},
"上海市": {},
"江苏省": {},
"浙江省": {},
"安徽省": {},
"福建省": {},
"江西省": {},
"山东省": {},
"河南省": {},
"湖北省": {},
"湖南省": {},
"广东省": {},
"广西壮族自治区": {},
"海南省": {},
"重庆市": {},
"四川省": {},
"贵州省": {},
"云南省": {},
"西藏自治区": {},
"陕西省": {},
"甘肃省": {},
"青海省": {},
"宁夏回族自治区": {},
"新疆维吾尔自治区": {},
"台湾省": {},
"香港特别行政区": {},
"澳门特别行政区": {},
}
console.log(obj)
for (const objKey in obj) {
}
// 1加载省数据
const province = Object.keys(obj).map((item) => `<option value="${item}">${item}</option>`)
document.querySelector(`[name='province']`).innerHTML += province.join(``)
// 2加载市,监听省change事件
document.querySelector(`[name='province']`).addEventListener('change', function () {
// 2-1获取当前选择的省
const province = this.value
//新增
// 2-2任何时刻,当用户点击省时,强制市、县为空
document.querySelector(`[name='city']`).innerHTML = `<option value="">--市--</option>`
document.querySelector(`[name='county']`).innerHTML = `<option value="">--区/县--</option>`
//新增
const city = Object.keys(obj[province]).map((item) =>
`<option value="${item}">${item}</option>`)
document.querySelector(`[name='city']`).innerHTML = city.join(``)
})
// 3加载县
document.querySelector(`[name='city']`).addEventListener('change', function () {
// 3-1获取当前选择的市
const city = this.value
//新增
// 3-2任何时刻,当用户点击市时,强制县为空
document.querySelector(`[name='county']`).innerHTML = `<option value="">--区/县--</option>`
//新增
const province = document.querySelector(`[name='province']`).value
// 3-3加载县
const county = Object.keys(obj[province][city]).map((item) =>
`<option value="${item}">${item}</option>`)
document.querySelector(`[name='county']`).innerHTML = county.join(``)
})
document.querySelector(`button`).addEventListener('click',function(){
document.querySelector(`[name='city']`).innerHTML = `<option value="">--市--</option>`
document.querySelector(`[name='county']`).innerHTML = `<option value="">--区/县--</option>`
document.querySelector(`[name='county']`).innerHTML = `<option value="">--区/县--</option>`
})
</script>
</body>
</html>