最近用 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 的值。
这样就可以实现省市区三级联动了。