本来填写订单的页面选地址是三级联动的
但是由于领导的要求,需要改成四级联动
解决思路
最开始用的是官方的 picker , 所以我去翻看了uniapp 的官网
我们需要用到的是多列模式
解决步骤
1. 先封装对应的请求
/*** 获取省市县街道的列表*/
export const getAddressList = (data) => request({url: '/system/region/list', method: 'get', data: data })
2. 在data内去定义对应的数据
3. 在页面的 created 钩子函数内去调用方法
data () {return {provinceList: [], // 地区列表province: [], //省数组city: [], //市数组district: [], //区数组street: [], //街道数组mulSelect: [], //四级联动显示数组,该数组的值为[[province],[city],[district],[street]]mulSelectId: [] ,// 四级联动的idprovinceId: 110000, //省的idcityId: 110101, //市的iddistrictId: 110101001,//区的idstreetId: '', // 镇/街道idaddress:''};
},
created() {this.getList('', '1')
},
methods: {// 获取地址列表async getList(id, level) {const data = {parentId: id,level: level}const res = await getAddressList(data)if (this.mulSelect.length !== 4) {if(level == 1) {this.province = res.data.datathis.getProvince();this.mulSelectId.push(res.data.data[0].id)this.mulSelect.push(this.province); this.getList(this.provinceId, '2')} else if (level == 2) {this.city = res.data.datathis.getCity();this.mulSelectId.push(res.data.data[0].id)this.mulSelect.push(this.city);this.getList(this.cityId, '3')} else if (level == 3) {this.district = res.data.datathis.getDistrict();this.mulSelectId.push(res.data.data[0].id)this.mulSelect.push(this.district);this.getList(this.districtId, '4')}} else {if(level == 1) {// this.provinceId = res.data.data[0].idconsole.log(id)this.mulSelectId[0] = idconsole.log(this.mulSelectId)this.getProvince(); this.getList(this.provinceId, '2')} else if (level == 2) {this.city = res.data.datathis.cityId = res.data.data[0].idthis.mulSelectId[1] = this.cityIdthis.getCity();this.mulSelect[1] = this.city;this.getList(this.cityId, '3')} else if (level == 3) {this.district = res.data.datathis.districtId = res.data.data[0].idthis.mulSelectId[2] = this.districtIdthis.getDistrict();this.mulSelect[2] = this.district;this.getList(this.districtId, '4')} else if (level == 4) {this.street = res.data.datathis.streetId = res.data.data[0].idthis.mulSelectId[3] = this.streetIdthis.getStreet();this.mulSelect[3] = this.street;}}},
}
因为这个接口需要两个参数 而第一层级的省份是不需要id,只需要层级 所以在created内去调用的时候 只用传一个参数
这个方法是分了两种情况
第一种情况是刚进入页面的时候去获取地区的时候 因为我们定义的列表 mulSelect 数据是空的,所以说,这个时候 发请求获取到的数据 就是向这个数组内去push
第二种情况是 当后续切换地区的时候 这个时候就不能用push了 只能对应的地方去替换原来的数据
例如: this.mulSelectId[1] = this.cityId
判断条件的话 我预想的比较好的方法就是通过去判断 mulSelect 数组的长度 因为最开始添加的时候length肯定是为0 的 但是这个时候就需要做一个小改动 因为不能直接写
if (this.mulSelect.length == 0) 一些特殊情况 例如北京市 的情况下 总共是只有三级的 然后切换到xx省之后 就有四层数据 这个时候第四层数据怎么去替换呢 只能说push进去
当然 这个方法是接收两个参数的 第一个是对应的id 第二个是层级
因为我们发请求的时候是需要判断层级的 所以我又加了一层if判断 目的是为了区分一下
4. 初次调用请求方法
在实际开发中,为了用户的体验效果 肯定是第一次把四级的数据都展示出来,但是一次只能发一次请求
这个时候层级就派上用场了 当为第一层的时候发第一个请求, 得到省级别的列表,先调另外的方法把列表添加进入 muSelect 数组内
请求成功的时候也是拿到了第一个省份的id,我们拿到id后 递归 调用自身 但是传层级为2和对应的省id,这个时候就进入到了层级为2的逻辑内了 其实和层级1一样 这一层级也是获取到对应的市列表,调用方法添加到数组内 ,然后再调用自身传递3 ...........依次循环,直到循环完四次循环
下面是图解
因为默认第一个北京 只有三层 所以写三层就够了
5. 切换时请求
切换时 绑定的事件 @columnchange="colChange"
// 地址改变触发colChange(e) {// console.log(e.detail);// console.log(this.mulSelect[0][e.detail.value])switch (e.detail.column){case 0://选择省this.mulSelect[1] =[]this.mulSelect[2] =[]this.mulSelect[3] =[]this.provinceId=this.mulSelect[0][e.detail.value].id;console.log(this.provinceId)this.getList(this.provinceId, e.detail.column+2 )break;case 1://选择市this.mulSelect[2] =[]this.mulSelect[3] =[]this.cityId = this.mulSelect[1][e.detail.value].id;this.getList(this.cityId, e.detail.column+2 )break;case 2://选择区this.mulSelect[3] =[]this.districtId = this.mulSelect[2][e.detail.value].id;this.getList(this.districtId, e.detail.column+2 )break;case 3://选择街道this.streetId = this.mulSelect[3][e.detail.value].idbreak;default:break;}},
触发该事件 事件的e内有一个 detail 里面有两个属性 一个是value 一个是column
value 是对应的层级下的索引
column 是对应的层级
我这里+2 是因为 1. 此处的层级也为索引 是从0开始的,而请求时是从1开始的
2. 得到第一层的id 应该去请求的是第二层的数据 所以还要+1
所以此处的处理逻辑和3差不多,只是多了一个切换 在对应的层级调用对应的接口
请求后的操作也有所区别 ,例如请求得到的数据是直接去赋值替换 不是push添加
再细节一点的地方就是: 发请求前 先把对应需要替换的值先赋值一个空值
6. 完整代码
// 1
<template><view class="input-wrapper"><view class="label">所属区县</view><view class="input-box"><picker class="input" mode="multiSelector" :range="mulSelect" :range-key="'fullname'" @change="pickerChange" @columnchange="colChange"><view class="region" :class="!address? 'placeholder' : ''">{{address || '请选择区域' }}</view></picker></view><view class="iconfont location" @click="handleLocation">定位</view></view>
</template>// 2
<script>import { getAddressList} from '@/api/add-house/add-house.js'export default {data () {return {provinceList: [], // 地区列表province: [], //省数组city: [], //市数组district: [], //区数组street: [], //街道数组mulSelect: [], //四级联动显示数组,该数组的值为[[province],[city],[district],[street]]mulSelectId: [] ,// 四级联动的idprovinceId: 110000, //省的idcityId: 110101, //市的iddistrictId: 110101001,//区的idstreetId: '', // 镇/街道idaddress:''};},created() {this.getList('', '1') },methods: {// 获取地址列表async getList(id, level) {const data = {parentId: id,level: level}const res = await getAddressList(data)if (this.mulSelect.length !== 4) {if(level == 1) {this.province = res.data.datathis.mulSelectId.push(res.data.data[0].id)this.mulSelect.push(this.province); this.getList(this.provinceId, '2')} else if (level == 2) {this.city = res.data.datathis.mulSelectId.push(res.data.data[0].id)this.mulSelect.push(this.city);this.getList(this.cityId, '3')} else if (level == 3) {this.district = res.data.datathis.mulSelectId.push(res.data.data[0].id)this.mulSelect.push(this.district);this.getList(this.districtId, '4')}// } else if (level == 4) {// this.street = res.data.data// this.mulSelectId.push(res.data.data[0].id)// this.mulSelect.push(this.street);// }} else {if(level == 1) {this.mulSelectId[0] = id this.getList(this.provinceId, '2')} else if (level == 2) {this.city = res.data.datathis.cityId = res.data.data[0].idthis.mulSelectId[0] = idthis.mulSelect[1] = this.city;this.getList(this.cityId, '3')} else if (level == 3) {this.district = res.data.datathis.districtId = res.data.data[0].idthis.mulSelectId[1] = idthis.mulSelect[2] = this.district;this.getList(this.districtId, '4')} else if (level == 4) {this.street = res.data.datathis.streetId = res.data.data[0].idthis.mulSelectId[2] = idthis.mulSelectId[3] = this.streetIdconsole.log(this.mulSelectId)this.mulSelect[3] = this.street;}}},// 选中的地址发生改变时触发pickerChange(e) {console.log(e,'change')//什么都不选的话,e.detail.value的值为[null,null,null,null]//只选择省的话,e.detail.value的值为[数字,null,null,null]//只选择市的话,e.detail.value的值为[数字,数字,null,null]//所以获取e.detail.value的值先判断是否为null,如果为null则取值为0for(var i=0;i<e.detail.value.length;i++){if(e.detail.value[i]===null){e.detail.value[i]=0;}}var s_province=this.mulSelect[0][e.detail.value[0]];//获取选中的省var s_city=this.mulSelect[1][e.detail.value[1]||0];//获取选中的市var s_district=this.mulSelect[2][e.detail.value[2]||0];//获取选中的区if(this.mulSelect[3].length !== 0) {console.log(this.mulSelect)var s_street=this.mulSelect[3][e.detail.value[3]||0];//获取选中的街this.address=s_province.fullname+s_city.fullname+s_district.fullname+s_street.fullname;} else {this.address=s_province.fullname+s_city.fullname+s_district.fullname}//赋值显示在页面},// 地址改变触发colChange(e) {// console.log(e.detail);// console.log(this.mulSelect[0][e.detail.value])switch (e.detail.column){case 0://选择省this.mulSelect[1] =[]this.mulSelect[2] =[]this.mulSelect[3] =[]this.provinceId=this.mulSelect[0][e.detail.value].id;console.log(this.provinceId)this.getList(this.provinceId, e.detail.column+2 )break;case 1://选择市this.mulSelect[2] =[]this.mulSelect[3] =[]this.cityId = this.mulSelect[1][e.detail.value].id;this.getList(this.cityId, e.detail.column+2 )break;case 2://选择区this.mulSelect[3] =[]this.districtId = this.mulSelect[2][e.detail.value].id;this.getList(this.districtId, e.detail.column+2 )break;case 3://选择街道this.streetId = this.mulSelect[3][e.detail.value].idbreak;default:break;}},}
</script>