【Mint-UI】Picker之省市区三级联动(动态获取数据)
前一段时间写了一个基于微信端的保险项目,用到了mint-ui的picker,当时在选择地区的三级联动这一块,确实徘徊很长时间,很大程度是因为不太理解mint-ui的文档,用了很多很复杂的方法,最后还是苦心钻研文档,才发现,官方提供的方法写起来非常简单。现在回过头来,觉得有必要记录一下,指引那些和我曾经一样懵懂的少年。ok,抒情到此为止,介绍一下背景,项目没有搭建vue脚手架,引入的vue和mint
前一段时间写了一个基于微信端的保险项目,用到了mint-ui的picker,当时在选择地区的三级联动这一块,确实徘徊很长时间,很大程度是因为不太理解mint-ui的文档,用了很多很复杂的方法,最后还是苦心钻研文档,才发现,官方提供的方法写起来非常简单。现在回过头来,觉得有必要记录一下,指引那些和我曾经一样懵懂的少年。ok,抒情到此为止,介绍一下背景,项目没有搭建vue脚手架,引入的vue和mint-ui的cdn,写法上有些许不同,但是思路完全一下,各位看官大人不必惊慌。我已经努力把代码整理的尽可能的详细,大家不要头晕,我只说重点。
首先展示一下效果图
HTML页面没什么好说的,应该没人会卡在这一部分:
<div class="weui-cell weui-cell_input font-size-8" style="background-color: white;" @click="openAreaPopup" >
<div class="weui-cell__hd">
<div class="weui-label">选择地区</div>
</div>
<div class="weui-cell__bd" >
<input name="isareastart" class="weui-input color-black" :value='areaValue' disabled />
</div>
<div class="weui-cell__ft weui-cell__ft_in-access"></div>
</div>
<mt-popup v-model="areaVisible" popup-transition="popup-fade" position="bottom" style="width: 100%;" >
<mt-picker :slots="areaList" value-Key="name" :show-toolbar="true" @change="selectArea">
<Slot>
<div class="confirmKey flex justify-content-between font-size-9 border-box">
<div class="color-grey" @click="closePopup">取消</div>
<div class="color-green" @click="sureArea">确定</div>
</div>
</Slot>
</mt-picker>
</mt-popup>
JS:
1、首先创建一个solts,确定picker的格式和初始数据
//注意这一级,二级,三级的含义,下边会经常提到级别。
areaList:[
{ //一级 省
flex: 1,
values: ["请选择"],
className: 'slot1',
textAlign: 'center'
}, {
divider: true,
content: '-',
className: 'slot1'
}, { //二级 市
flex: 1,
values: ["请选择"],
className: 'slot1',
textAlign: 'center'
},{
divider: true,
content: '-',
className: 'slot1'
},{ //三级 区
flex: 1,
values: ["请选择"],
className: 'slot1',
textAlign: 'center'
}
],
values 为每一级slot的值,className 为这一级的样式名称,textAlign为这一级的文本对齐方式。
2、因为地区的数据都是动态请求后台获取的,所以初始化的时候至少要给areaList的第一级省的数据加载出来并放入areaList[0].values 中,否则会出现用户首次选择地区的时候没有数据。
beforeMount:function(){
},
mounted:function(){
let that = this;
axios.post('ajax?_ajaxurl=arealist')
.then(function (res) {
console.log(res);
that.areaList[0].values=res.data.area_list;
})
.catch(function (error) {
console.log(error);
});
},
在beforeMount和mounted中请求数据都是可以的,看个人喜好。
我们公司返回的地区数据为下图所示:
3、我们需要了解picker实例上的方法
setSlotValues(index, values):设定给定 slot 的备选值数组 index从0开始。
getValues():获取所有 slot 目前被选中的值(分隔符 slot 除外)
这两个方法我们将会用到
思路是这样:
① 用户选择省后,得到省的id ;
② 通过省的id进行axios请求获取到该省下市的数据;
③ 用setSlotValues(index, values)方法将市的数据放入areaList的二级中;
④ 用户选择市后,获取到市的id;
⑤ 通过市的id进行axios请求获取到该市下区的数据;
⑥ 用setSlotValues(index, values)方法将区的数据放入areaList的三级中;
⑦ 用getValues()获取到用户选择的数据
需要注意的是:
axios请求一般为异步请求,数据不能及时获取,从而导致③④⑤⑥⑦步不能正常进行,
所以这里我们要做一个处理,将axios请求转换为同步,此处使用到promise;
//调取地区列表的函数
area(id){
let that = this;
//因为我们需要拿到axios请求的数据,来进行下一个axios的请求,
//所以我们这里使用promise对象,将异步转换为同步。
let promise= new Promise(function(resolve,reject){
let o={
pid:id
}
axios.post('ajax?_ajaxurl=arealist',Qs.stringify(o))
.then(function (res) {
resolve(res.data.area_list);
})
.catch(function (error) {
console.log(error);
});
})
return promise;
},
没了解过promise的可以移步https://blog.csdn.net/NAMECZ/article/details/84954418,让你30秒快速上手promise。
所以这一块我们的代码是这样子的:
// 选择地区
selectArea(picker,values){
let that = this;
console.log("values",values);//你选中的值
that.area(values[0]["id"]).then(function(data){ //通过一级 省的id 获取市的列表
picker.setSlotValues(1,data);//将市的地区列表放入 areaList的二级列表中
});
that.area(values[1]["id"]).then(function(data){//通过 二级 市的id 获取区域的列表
picker.setSlotValues(2,data);//将区的地区列表放入 areaList的三级列表中
});
let arr = picker.getValues();
that.cityName=`${arr[0].name}-${arr[1].name}-${arr[2].name}`;
that.cityCode={
province:arr[0].adcode,
city:arr[1].adcode,
county:arr[2].adcode
};
},
4、到此为止三级联动的功能已经实现了,下边贴出完整代码
new Vue({
el:"#app",
data:{
handler:function(e){e.preventDefault();}, //阻止body滑动
areaList:[
{ //一级 省
flex: 1,
values: ["请选择"],
className: 'slot1',
textAlign: 'center'
}, {
divider: true,
content: '-',
className: 'slot1'
}, { //二级 市
flex: 1,
values: ["请选择"],
className: 'slot1',
textAlign: 'center'
},{
divider: true,
content: '-',
className: 'slot1'
},{ //三级 区
flex: 1,
values: ["请选择"],
className: 'slot1',
textAlign: 'center'
}
],
flag:false,//初始时禁止picker自动加载
areaVisible:false,//初始选择地区弹窗为关闭状态
areaValue:"省-市-区", //页面上显示的内容
cityName:"",//最终选中的地区的名字
cityCode:"",//最终选中的地区的id
},
watch:{
areaVisible:function(newvs,oldvs){ //判断选择地区弹窗的状态
console.log("newvs",newvs);
console.log("oldvs",oldvs);
if(newvs){ //如果areaVisible的值为true,说明弹窗出现
this.closeTouch(); //阻止body滑动
}else{ //如果areaVisible的值为false,说明弹窗隐藏
this.openTouch();//恢复body滑动
}
},
},
beforeMount:function(){
},
mounted:function(){
let that = this;
axios.post('ajax?_ajaxurl=arealist')
.then(function (res) {
console.log(res);
that.areaList[0].values=res.data.area_list;
})
.catch(function (error) {
console.log(error);
});
},
methods:{
// 打开选择地区的弹窗
openAreaPopup(){
let that = this;
that.areaVisible=true;
that.flag=true;
},
// 选择地区
selectArea(picker,values){
let that = this;
// console.log("picker",picker);
// console.log("values",values);
if(that.flag){
that.area(values[0]["id"]).then(function(data){ //通过一级 省的id 获取市的列表
picker.setSlotValues(1,data);//将市的地区列表放入 areaList的二级列表中
});
that.area(values[1]["id"]).then(function(data){//通过 二级 市的id 获取区域的列表
picker.setSlotValues(2,data);//将区的地区列表放入 areaList的三级列表中
});
let arr = picker.getValues();
// console.log(arr);
that.cityName=`${arr[0].name}-${arr[1].name}-${arr[2].name}`;
that.cityCode={
province:arr[0].adcode,
city:arr[1].adcode,
county:arr[2].adcode
};
console.log("picker");
}
},
//关闭弹窗
closePopup(){
let that = this;
that.areaVisible=false;
},
//确定地区
sureArea(){
let that = this;
that.areaValue=that.cityName;
that.areaVisible=false;
},
//调取地区列表的函数
area(id){
let that = this;
//因为我们需要拿到axios请求的数据,来进行下一个axios的请求,
//所以我们这里使用promise对象,将异步转换为同步。
let promise= new Promise(function(resolve,reject){
let o={
pid:id
}
axios.post('ajax?_ajaxurl=arealist',Qs.stringify(o))
.then(function (res) {
resolve(res.data.area_list);
})
.catch(function (error) {
console.log(error);
});
})
return promise;
},
/*解决iphone页面层级相互影响滑动的问题*/
closeTouch:function(){
document.getElementsByTagName("body")[0].addEventListener('touchmove',
this.handler,{passive:false});//阻止默认事件
console.log("closeTouch haved happened.");
},
openTouch:function(){
document.getElementsByTagName("body")[0].removeEventListener('touchmove',
this.handler,{passive:false});//打开默认事件
console.log("openTouch haved happened.");
},
}
})
今天的分享,就是这些,其实很长时间没看这些代码了,今天回顾一下,发现还有很多能够优化的地方,希望阅读过这篇文章的同学能够自己思考并写出更加优质的代码。还望往来的朋友不要吝啬,给我点个小小的赞,您的随手之劳,对我来说是很大的动力。抱拳~
更多推荐
所有评论(0)