最近用 Vue 开发一个项目,需要实现一个省市区三级联动的功能。
使用的是饿了么团队的移动端组件库 Mint UI 中的 Picker 组件,官方的文档也是十分的不详细。
我期间遇到了不少问题,踩了一些坑,下次记录一下,希望能对大家和以后的自己有所帮助。
Mint UI 的使用,我就不再赘述的,大家需要的话可以根据官方文档进行下载和使用。下面开始进入正题:
我这里使用的是后端提供的省市区数据接口,为了方便最下面代码的理解,我再次贴一下我所使用的数据:省市区三级联动数据
您也可以直接下载我提供的 json 文件:点击下载
picker 的使用(HTML):我这里搭配了 popup 使用。
<mt-popup v-model="popupVisible" position="bottom"> <div class="pickerTitle"> <a-button type="link" @click="popupClose">取消</a-button> <h4>选择地区</h4> <a-button type="link" @click="handlePopup">确定</a-button> </div> <mt-picker v-if="addSlots.length === 0"></mt-picker> <mt-picker v-else :slots="addSlots" value-key="name" :itemHeight="50" :visibleItemCount="3" @change="addressChange"> </mt-picker> </mt-popup>
JS 部分代码:
因为保存数据时,后台不进去要省市区的名字,而且需要省市区的 id ,所以 values 我是这样写的。
因为北京只有市和区,没有省的数据,所以初始化的时候没有设置第三个 slot 的值。
data () { return { popupVisible: false, addData: [], addSlots: [{ flex: 1, //对应 slot CSS 的 flex 值 values: [ //省份数组 { code: '', name: '', key: 0, } ], className: 'slot1', //对应 slot 的类名 textAlign: 'right' //对应 slot 的对齐方式 }, { flex: 1, values: [ { code: '', name: '', key: 0, } ], className: 'slot2' }, { flex: 1, values: undefined, className: 'slot3', textAlign: 'left' }], addValue: [//确定时赋值 {name:'',code:''},//省 {name:'',code:''},//市 {name:'',code:''},//区 ], addValue1: [//选中的数据 {name:'',code:''},//省 {name:'',code:''},//市 {name:'',code:''},//区 ], } }, methods: { getRegion(){//获取省市区数据,需要一个初始值。 let that = this, add = [], add1 = [], pd = that.addData, cd = pd[0].child; for (let prop in pd) { add.push({name: pd[prop].title, code: pd[prop].ad_code, key: Number(prop)}) } that.addSlots[0].values = add //设置组件的省数据 for (let prop in cd) { add1.push({name: cd[prop].title, code: cd[prop].ad_code, key: Number(prop)}) } that.addSlots[1].values = add1 //设置组件的市的数据 }, popupShow (type) { let that = this; that.popupVisible = true; }, popupClose () { this.popupVisible = false; }, addressChange (picker, values) {//选中数据改变时 let that = this; if (that.addData[values[0].key]) { //判断省的key值,类似于 v-if 的效果(可以不加,但是会报错,很不爽) let cd = that.addData[values[0].key].child, //市的数据 ad = cd[values[1].key].child, //区的数据 c = [], a = []; for (let i in cd) { c.push({name: cd[i].title, code: cd[i].ad_code, key: Number(i)}) //循环出市的数据 } picker.setSlotValues(1, c);//赋给第二个 slot for (let i in ad) { a.push({name: ad[i].title, code: ad[i].ad_code, key: Number(i)}) //循环出区的数据 } picker.setSlotValues(2, a); //复制给第三个 slot for (let i in values){ // 将选中的数据缓存一下 if (values[i]) { that.addValue1[i].code = values[i].code; that.addValue1[i].name = values[i].name; } else { that.addValue1[i].code = ''; that.addValue1[i].name = ''; } } } }, handlePopup () { //点击确实时,将缓存的数据赋值给 addValue ,实现前端显示。 for (let i in this.addValue){ if (this.addValue[i]) { this.addValue[i].code = this.addValue1[i].code; this.addValue[i].name = this.addValue1[i].name; } } this.popupVisible = false; } },
遇到的问题:
开始我我封装了一个方法,在 picker 变化时,直接修改 this.addSlots ,发现在滑动第二个 slot 的时候不能检测数据变化,无法缓存数据。
需要使用 picker 的 picker.setSlotValues(2, a)
属性给 slot 赋值。
picker.setSlotValues(index, value):
这里的 index
是 slot 的下标,2 就代表第三个 slot。
value
代表 slot 的 values 的值。
这样就可以实现省市区三级联动了。