el-cascader多选三级省市区(全选省/市 保存的是省市Code)
业务场景:需求是多选三级省市区, 开发一个区域组功能(而且产品也是比较希望使用el-cascader来进行实现)
需求实现截图:
那就开始整呗, 找ElementUI的组件去实现这个
// Vue的基本样式
<el-cascader
v-model="regionList"
ref="cascader"
:options="treeList"
:props="{
multiple: true,
value: 'code',
label: 'name',
checkStrictly: false
}"
style="width:100%;"
:key="regionKeys"
clearable
filterable
collapse-tags></el-cascader>
然后就踩了第一个坑
因为cascader组件如果设置子父级关联的情况下组件内部实际上保存的是最后一级的code // 组件接收的值 例 [[110000, 110100, 110101]] 这样代表的就是选中 北京 - 北京市市辖区 - 东城区
然后全国3600+的区县, 全都保存到数据库的话,
一方面不方便查询
另一方面存储数据量过大会影响接口效率
不过还好组件内部为我们提供了getCheckedNodes()方法用于获取组件已选中节点
this.$refs['cascader'].getCheckedNodes()
然后我们就可以对选中数据做去重的功能
比如全选省后, 只保存省的code, 省所有的下级都会被筛选掉(市级同理)
在这里给读者提供一种思路
省code == > 后四位必定是0000
市code ==> 后两位必定是00, 且前两位加上0000就是它所属的省
区县code ==> 前两位加上0000就是它所属的省, 前四位加上00就是它所属的市
我们根据这个逻辑来筛选选中的节点
/*
cityList ==> this.$refs['cascader'].getCheckedNodes()
从cascader组件获取的选中数据(每项并非code, 而是节点)
*/
function getCityCode (cityList) {
const list = cityList.map(item => {
return item.value
})
// 首先将全部的code拿到整合成一个数组
const selectCityList = [] // 整合(拼装后)的数组
cityList.forEach(item => {
const proCode = item.value.toString().substr(2)
const cityCode = item.value.toString().substr(4, 2)
// 如果当前项的后四位为0000表示它是一个省份直接添加进新数组中
if (proCode == '0000') {
// console.log('选择的是省份')
selectCityList.push(item.value)
} else if (cityCode == '00') {
const code = (item.value.toString().substr(0, 2) + '0000') * 1
// 如果是城市的话, 则需要判断这个城市所属的省份有没有在数组里面,
// 有当前城市的省份 ==> 不添加进数据
// 没有省份 ==> 添加进数据
if (!list.includes(code)) {
selectCityList.push(item.value)
}
// console.log('选择的是城市')
} else {
const code = (item.value.toString().substr(0, 4) + '00') * 1
const proCode = (item.value.toString().substr(0, 2) + '0000') * 1
// 如果是区县的话, 则需要判断这个城市所属的省份和城市有没有在数组里面
// 有当前区县的省份或者城市 ==> 不添加进数据
// 没有省份和城市 ==> 添加进数据
if (!list.includes(code) && !list.includes(proCode)) {
selectCityList.push(item.value)
}
// console.log('默认选择的是区县')
}
})
// console.log(selectCityList, '选中列表')
return selectCityList.length ? selectCityList : []
}
由上述代码可以筛选掉多级的省市区, 只保留最大的一级
!!如果需要回显对应的地区, 则需要使用跟上面类似的方法将数据拼接起来显示(ElementUI的el-cascader不支持根据省code选中省...)
/**
ret.areaVoList ==> 筛选后的省市列表
treeList ==> 省市区三级的数据列表
**/
ret.areaVoList.forEach(item => {
const code = item.locationCode + ''
if (code.substr(2) == '0000') {
// console.log('保存的是省份')
const proList = this.treeList.filter(item => item.code === code * 1)
/**
* 末尾为0000说明是省份
* 需要从省市区数据把当前省份筛选出来
* 因为回显需要省市区三级code
* 所以这里需要循环取值
*/
proList.forEach(proItem => {
// console.log(proItem.code,'省')
if (proItem.children && proItem.children.length) {
proItem.children.forEach(cityItem => {
// console.log(cityItem.code,'市')
/**
* 如果当前市有区县 ==> 循环取区
* 没有区县 ==> 直接添加[省,市]
*/
if (cityItem.children && cityItem.children.length) {
cityItem.children.forEach(regionItem => {
// console.log(regionItem.code, '区县')
this.regionList.push([proItem.code * 1, cityItem.code * 1, regionItem.code * 1])
})
} else {
this.regionList.push([proItem.code * 1, cityItem.code * 1])
}
})
}
})
} else if (code.substr(4, 2) == '00') {
const proCode = code.substr(0, 2) + '0000'
const proList = this.treeList.filter(item => item.code === proCode * 1)
// console.log('保存的是市')
proList.forEach(proItem => {
// console.log(proItem.code,'省')
proItem.children.forEach(cityItem => {
// console.log(cityItem.code,'市')
/**
* 如果当前市有区县 ==> 循环取已经选择的区
* 没有区县 ==> 直接添加[省,市]
*/
if(cityItem.children && cityItem.children.length) {
cityItem.children.forEach(regionItem => {
// console.log(regionItem.code, '区县')
if (cityItem.code === code * 1) {
this.regionList.push([proItem.code * 1, cityItem.code * 1, regionItem.code * 1])
}
})
} else if (cityItem.code === code * 1) {
this.regionList.push([proItem.code * 1, cityItem.code * 1])
}
})
})
// console.log('保存的是城市')
} else {
const proCode = code.substr(0, 2) + ''
const cityCode = code.substr(2, 2) + ''
// console.log('默认区县')
this.regionList.push([`${proCode}0000` * 1, `${proCode}${cityCode}00` * 1, code * 1])
}