foreword
The selection of provinces and cities is a common functional requirement in many mobile applications, and the area component of vant has provided us with a very useful selection scheme. However, in some scenarios, we need to re-encapsulate the area and provide a more customized function of selecting provinces and districts to meet more specific business needs. This article will introduce how to re-encapsulate area in vant , and provide some practical encapsulation techniques and methods to help you achieve a more perfect selection of provinces and cities.
Implementation ideas
- First define a subcomponent page to encapsulate the selector;
- Introduce and register the encapsulation component (subcomponent) in the parent component (the page used), and then use it in the page. In the parent component, bind multiple attributes to the label (registered component name), and the attribute needs to be passed to mount The value of is received by
props
receiving data in the subcomponent (encapsulation file); - Customize the determined event in the child component. After calling this event, the child component sends
this.$emit('自定义事件名',要传递的数据)
the data that the parent component can listen to, and finally the parent component listens to the child component event, calls the event and receives the passed data.
Install
vant
The official provides a default data of provinces and cities, which can be @vant/area-data
imported through:
npm i @vant/area-data
defined parameters
parameter | describe |
---|---|
selectValue | bind valuemodel |
keyValue | bound key field |
columnsNum | bound value field |
rules | The bound option data source |
required | Whether to display red * check |
package file
<template>
<div>
<van-field v-model="textValue" v-bind="$attrs" :name="$attrs.name" :placeholder="placeholder" :rules="rules" :required="required"
:readonly="readonly" :is-link="islink" @click="show = !show" />
<van-popup v-model="show" position="bottom" :overlay="true" :close-on-click-overlay="true">
<van-area :area-list="areaList" :columns-num="columnsNum" :columns-placeholder="columnsplaceholder" @confirm="onConfirm"
@cancel="show = !show" />
</van-popup>
</div>
</template>
<script>
import {
areaList } from "@vant/area-data";
export default {
props: {
required: {
type: Boolean,
},
readonly: {
type: Boolean,
},
islink: {
type: Boolean,
},
columnsNum: {
type: Number,
},
rules: {
type: Array,
},
selectValue: {
type: String,
},
keyValue: {
//code 返回区县码 name 返回区县名称
type: String,
},
},
data() {
return {
areaList,
show: false,
textValue: "",
selectOptions: [],
placeholder: "",
columnsplaceholder: ["请选择", "请选择", "请选择"],
provinceList: null,
cityList: null,
countyList: null,
province: "", //省
city: "", //市
county: "", //区县
};
},
methods: {
onConfirm(areaData) {
// 判断打开选择器后是否必填省/市/区
if (this.columnsNum == "1") {
this.provinceOn(areaData);
} else if (this.columnsNum == "2") {
this.provinceCityOn(areaData);
} else {
this.provincesMunicipalitiesOn(areaData);
}
},
// 省时必填校验
provinceOn(areaData) {
let province = areaData[0];
if (province.name) {
} else {
this.$toast("请选择省");
return;
}
this.acquireOn(areaData);
},
// 省市时必填校验
provinceCityOn(areaData) {
let province = areaData[0];
let city = areaData[1];
if (province.name) {
} else {
this.$toast("请选择省");
return;
}
if (city.name) {
} else {
this.$toast("请选择市");
return;
}
this.acquireOn(areaData);
},
// 省市区时必填校验
provincesMunicipalitiesOn(areaData) {
let province = areaData[0];
let city = areaData[1];
let area = areaData[2];
if (province.name) {
} else {
this.$toast("请选择省");
return;
}
if (city.name) {
} else {
this.$toast("请选择市");
return;
}
if (area.name) {
} else {
this.$toast("请选择区");
return;
}
this.acquireOn(areaData);
},
// 校验完后执行确定方法赋值name/code
acquireOn(areaData) {
// 获取选中name/code值
let names = "";
let codes = "";
areaData.map((item, index) => {
if (!item) {
return "";
}
if (index > 0) {
names += "/" + item.name;
codes += "/" + item.code;
} else {
names += item.name;
codes += item.code;
}
});
if (this.keyValue == "code") {
this.textValue = codes;
} else {
this.textValue = names;
}
this.show = !this.show;
this.$emit("confirm", this.textValue);
},
//通过code 值获取地区name
getNameByCode(value, list) {
let name = "";
if (!value) {
return;
}
Object.keys(list).forEach((key) => {
if (value.toString() == key.toString()) {
name = list[key];
}
});
return name;
},
//地区回显
getValue(type) {
if (!this.selectValue || !this.selectValue.length) {
//如果 value传值不存在
this.textValue = "";
return;
}
let selectList = this.selectValue.split("/");
let provinceName,
cityName,
countyName = "";
switch (type) {
case "code":
//如果父级传值是 code
if (Number(this.columnsNum) == 1) {
//省
provinceName = this.getNameByCode(selectList[0], this.provinceList);
this.textValue = provinceName;
} else if (Number(this.columnsNum) == 2) {
//省
provinceName = this.getNameByCode(selectList[0], this.provinceList);
//市
cityName = this.getNameByCode(selectList[1], this.cityList);
this.textValue = provinceName + "/" + cityName;
} else {
//省
provinceName = this.getNameByCode(selectList[0], this.provinceList);
//市
cityName = this.getNameByCode(selectList[1], this.cityList);
//区
countyName = this.getNameByCode(selectList[2], this.countyList);
this.textValue = provinceName + "/" + cityName + "/" + countyName;
}
break;
case "name":
//如果父级传值是 name
this.textValue = this.selectValue;
break;
}
},
},
watch: {
// json数据
areaList: {
handler(newVal) {
if (newVal) {
let length = Object.keys(newVal).length;
if (length) {
this.cityList = newVal.city_list;
this.countyList = newVal.county_list;
this.provinceList = newVal.province_list;
}
}
},
immediate: true,
deep: true,
},
// 控制选择完整省市区还是部分
columnsNum: {
handler(newVal) {
switch (newVal) {
case 1:
this.placeholder = "省";
this.columnsplaceholder = ["请选择"];
break;
case 2:
this.placeholder = "省/市";
this.columnsplaceholder = ["请选择", "请选择"];
break;
default:
this.placeholder = "省/市/区";
this.columnsplaceholder = ["请选择", "请选择", "请选择"];
}
},
immediate: true,
},
selectValue: {
handler(newValue) {
this.$nextTick(() => {
if (this.keyValue) {
this.getValue(this.keyValue);
}
});
},
immediate: true,
},
keyValue: {
handler(newValue) {
if (newValue) {
this.getValue(newValue);
}
},
immediate: true,
},
},
};
</script>
use file
<template>
<div>
<van-form validate-first>
<AreaSelect name="cjPovo" label="车辆注册地" :selectValue="cjPovo" :readonly="true" :keyValue="`name`" :columnsNum="3"
@confirm="areaConfirm" :required="true" :rules="rules.cjPovo" />
<div class="btnBomBox">
<van-button round size="small" block @click="submitOn" type="info">提交</van-button>
</div>
</van-form>
</div>
</template>
<script>
import AreaSelect from "@/components/areaSelect/index";
export default {
components: {
AreaSelect,
},
data() {
return {
cjPovo: "",
rules: {
cjPovo: [
{
required: true,
message: "请选择车辆注册地",
},
],
},
};
},
methods: {
// 点击确定
areaConfirm(data) {
this.cjPovo = data;
},
// 提交
submitOn() {
console.log(this.cjPovo);
},
},
};
</script>
<style scoped>
.btnBomBox {
padding: 0px 16px;
display: flex;
justify-content: center;
}
</style>