工作中会经常会遇到选择省市区三级联动的需求,每次都有不同的需求,比如有不限,比如动态添加多个,比如宽度自定义,比如回显,回显类型不确定。。。等等。。。
每次都要根据需求定制,现在闲下来,将这些暂时遇到的需求整合到了一个组件里面,希望可以暂时救一下在花样需求的沼泽里出不来的人。
个人写的,肯定有可优化的地方,肯定有覆盖不到的地方。请见谅~,欢迎留下你的只言片语,足够我醍醐灌顶~~(不会成语的author,不是一个号前端)
支持一下需求:
- 基于element-ui写的,可自行更换或者用原生;
- 省市区三级,暂时不支持四级;
- 省市区列表是否包含"不限",可自行从父组件传参,参数:unlimit,取值:true - 有不限,false - 无不限
- 宽度自定义,可自行从父组件传参,参数:pWidth:省宽度,cWidth:市宽度,aWidth:区宽度
- 支持添加多个,如需记录index,传参:fatherIndex
- 地址map前端写死,如有改动,自行改动。
一、引入地址map依赖文件:map.js
地址:https://my.oschina.net/wsxiao/blog/4295971
二、地址选择下拉框子组件
<!--
@Author: DKing
@Desc: 三级联动
@Date: 2020-04-30
-->
<template>
<div>
<el-select
v-model="areaParams.provinceCode"
@change="choseProvince"
clearable
placeholder="请选择"
class='el-select-adress el-select-adress-p'
>
<el-option
v-for="item in defaultProvince"
:key="item.id"
:label="item.value"
:value="item.id">
</el-option>
</el-select>
<el-select
v-model="areaParams.cityCode"
clearable @change="choseCity"
placeholder="请选择"
class='el-select-adress el-select-adress-c'
>
<el-option
v-for="item in cityArray"
:key="item.id"
:label="item.value"
:value="item.id">
</el-option>
</el-select>
<el-select
v-model="areaParams.areaCode"
clearable @change="choseBlock"
placeholder="请选择"
class='el-select-adress el-select-adress-a'
>
<el-option
v-for="item in areaArray"
:key="item.id"
:label="item.value"
:value="item.id">
</el-option>
</el-select>
</div>
</template>
<script>
import {AREA} from "../filters/map";
import {checkNull} from "../filters/filters";
import Vue from 'vue'
export default {
props:{
// 回显参数
editAreaParams: null,
// 省下拉框的宽度
pWidth:{
type: String,
},
// 市下拉框的宽度
cWidth:{
type: String,
},
// 区下拉框的宽度
aWidth:{
type: String,
},
// 父组件的index 适用于添加过个地址
fatherIndex:{
type: Number
},
// 是否有 不限 true:有,false:无
unlimit:{
type: Boolean || String,
default: false
}
},
data () {
return {
mapJson: AREA,
defaultProvince: [],
defaultCity: [],
defaultArea: [],
cityArray: [],
areaArray: [],
editAreaParamsTemp: this.editAreaParams,
unlimitTemp: this.unlimit == true || this.unlimit == 'true',
areaParams: {
provinceCode: '',
cityCode: '',
areaCode: ''
},
queryParam:{
province: '',
city: '',
area: ''
} ,//给父传递参数
queryParamText:{
province: '',
city: '',
area: ''
}
}
},
created(){
// 宽度自定义
this.$nextTick(() =>{
let pDom = document.getElementsByClassName('el-select-adress-p') || []
let cDom = document.getElementsByClassName('el-select-adress-c') || []
let aDom = document.getElementsByClassName('el-select-adress-a') || []
for(let p of pDom){
p.children[0].style.width = this.pWidth
}
for(let c of cDom){
c.children[0].style.width = this.cWidth
}
for(let a of aDom){
a.children[0].style.width = this.aWidth
}
})
// 初始化数据
this.getCityData().then(res => {
if(!checkNull(this.editAreaParamsTemp)){
if(typeof(this.editAreaParamsTemp) == 'string'){
this.editAreaParamsIsStrHandel()
}
this.areaParams = this.editAreaParamsTemp;
this.showDataHandel(this.areaParams.provinceCode);
}
});
},
methods:{
// 加载地点数据,三级
getCityData:function(){
return new Promise((resolve, reject)=>{
var that = this;
// 省市区数据分类
for (var item in this.mapJson) {
if (item.match(/0000$/)) {//省
that.defaultProvince.push({id: item, value: this.mapJson[item], children: []})
} else if (item.match(/00$/)) {//市
that.defaultCity.push({id: item, value: this.mapJson[item], children: []})
} else {//区
that.defaultArea.push({id: item, value: this.mapJson[item]})
}
}
this.unlimitTemp && that.defaultProvince.unshift({id:'不限', vlaue:'不限', children:[]})
resolve('success_p')
// 分类市级
for (var index in that.defaultProvince) {
for (var index1 in that.defaultCity) {
if (that.defaultProvince[index].id.slice(0, 2) === that.defaultCity[index1].id.slice(0, 2)) {
that.defaultProvince[index].children.push(that.defaultCity[index1])
}
}
this.unlimitTemp && that.defaultProvince[index].children.unshift({id:'不限', vlaue:'不限', children:[{id:'不限', value:'不限'}]})
}
resolve('success_c')
// 分类区级
for(var item1 in that.defaultCity) {
for(var item2 in that.defaultArea) {
if (that.defaultArea[item2].id.slice(0, 4) === that.defaultCity[item1].id.slice(0, 4)) {
that.defaultCity[item1].children.push(that.defaultArea[item2])
}
}
this.unlimitTemp && that.defaultCity[item1].children.unshift({id:'不限', vlaue:'不限'})
}
resolve('success_a')
})
},
// 选省
choseProvince:function(e) {
for (var index2 in this.defaultProvince) {
if (e === this.defaultProvince[index2].id || e === this.defaultProvince[index2].value) {
this.cityArray = this.defaultProvince[index2].children
this.areaArray = this.defaultProvince[index2].children[0].children;
// 省
this.queryParam.province = this.defaultProvince[index2].id
this.queryParamText.province = this.defaultProvince[index2].value
// 市
this.areaParams.cityCode = this.defaultProvince[index2].children[0].id;
this.queryParam.city = this.cityArray[0].id
this.queryParamText.city = this.cityArray[0].value
// 区
this.areaParams.areaCode = this.defaultProvince[index2].children[0].children[0].id
this.queryParam.area = this.areaArray[0].id
this.queryParamText.area = this.areaArray[0].value
this.$emit("queryParamText",this.queryParamText, this.fatherIndex)
this.$emit("getAreaParam",this.queryParam, this.fatherIndex)
}
}
},
// 回显
showDataHandel: function(e){
console.log('回显:',e)
for (var index2 in this.defaultProvince) {
if (e === this.defaultProvince[index2].id || e === this.defaultProvince[index2].value) {
e = this.defaultProvince[index2].id
// 省
this.areaParams.provinceCode = this.defaultProvince[index2].id
this.queryParam.province = e
this.queryParamText.province = this.defaultProvince[index2].value
this.cityArray = this.defaultProvince[index2].children
console.log('城市列表:',this.cityArray)
// 得到选择的城市列表
let currentCity = this.cityArray.filter((cityItem, cityIndex) =>{
return cityItem.id == this.areaParams.cityCode || cityItem.value == this.areaParams.cityCode
})[0]
console.log('当前选择城市:', currentCity)
this.queryParam.city = currentCity == undefined? "不限" : currentCity.id
this.queryParamText.city = currentCity == undefined? "不限" : currentCity.value
this.areaParams.cityCode = currentCity == undefined? "不限" : currentCity.id
// 得到选择的区县列表
this.areaArray = currentCity.children
let currentArea = this.areaArray.filter((areaItem, areaIndex) => {
return areaItem.id == this.areaParams.areaCode || areaItem.value == this.areaParams.areaCode
})[0]
console.log('当前选择区域:',currentArea)
this.queryParam.area = currentArea == undefined? "不限" : currentArea.id;
this.queryParamText.area = currentArea == undefined? "不限" : currentArea.value
this.areaParams.areaCode = currentArea == undefined? "不限" : currentArea.id
this.$emit("queryParamText",this.queryParamText, this.fatherIndex)
this.$emit("getAreaParam",this.queryParam, this.fatherIndex)
}
}
},
// 字符串转换 例:北京市-北京市-东城区
editAreaParamsIsStrHandel(){
let array = this.editAreaParamsTemp.split('-')
this.editAreaParamsTemp = {
provinceCode: array[0],
cityCode: array[1],
areaCode: array[2]
}
},
// 选市
choseCity:function(e) {
for (var index3 in this.defaultCity) {
if (e === this.defaultCity[index3].id) {
this.areaArray = this.defaultCity[index3].children
this.areaParams.areaCode = this.defaultCity[index3].children[0].id
this.queryParam.city = e
this.queryParam.area = this.areaArray[0].id
this.queryParamText.city = this.defaultCity[index3].value
this.queryParamText.area = this.areaArray[0].value
this.$emit("queryParamText",this.queryParamText, this.fatherIndex)
this.$emit("getAreaParam",this.queryParam, this.fatherIndex)
}
}
},
// 选区
choseBlock:function(e) {
for(let item in this.areaArray){
if(e === this.areaArray[item].id){
this.queryParamText.area = this.areaArray[item].value
this.queryParam.area = this.areaArray[item].id
this.areaParams.areaCode = this.areaArray[item].id
this.$emit("queryParamText",this.queryParamText, this.fatherIndex)
this.$emit("getAreaParam",this.queryParam, this.fatherIndex)
}
}
}
},
}
</script>
三、父组件引入组件并使用
1、添加地址功能
- Template:
<!-- 简单使用 -->
<area-linkAge @getAreaParam='getAreaParam' @queryParamText='queryParamText'></area-linkAge>
<!-- 多个、含有不限,自定义宽高 -->
<areaLinkAgeVue pWidth="120px" cWidth="120px" aWidth="120px" @queryParamText='queryParamText' :fatherIndex='index' unlimit='true'/>
- script
import areaLinkAge from "../../components/areaLinkAge";
components: {
'area-linkAge': areaLinkAge,
},
data() {
return {
addressParam: {
province: '',
city: '',
area: '',
provinceText: '',
cityText: '',
areaText: '',
}
}
},
methods: {
// 获取子组件选择区域后的数据 - 地址code
getAreaParam(val){
this.addressParam.province = val.province;
this.addressParam.city = val.city;
this.addressParam.area = val.area;
},
// 获取子组件选择区域后的数据 - 地址Text
getAreaParam(val){
this.addressParam.provinceText = val.provinceText;
this.addressParam.cityText = val.cityText;
this.addressParam.areaText = val.areaText;
}
}
2、回显地址,支持多类型
(1)、支持类型举例:
- "北京市-北京市-朝阳区"
- "不限"、"不限-不限"
- "不限-不限-不限"
- {provinceCode:'11000', cityCode:'110100', areaCode:'110105'}
- {provinceCode:'北京市', cityCode:'北京市', areaCode:'朝阳区'}
(2)、Template
<!-- 简单使用 -->
<area-linkAge @getAreaParam='getAreaParam' @queryParamText='queryParamText' :editAreaParams='editAreaParams' v-if="addrVisible"></area-linkAge>
<!-- 多个、含有不限,自定义宽高 -->
<div v-for="(addr,index) of workAddress">
<areaLinkAgeVue pWidth="120px" cWidth="120px" aWidth="120px" :editAreaParams='addr' @queryParamText='queryParamText' :fatherIndex='index' unlimit='true'/>
</div>
Tip:因为地址回显的信息是异步请求回来的,所以需要添加v-if,当数据回来是将v-if设置为true;
(3)、script
import areaLinkAge from "../../components/areaLinkAge";
components: {
'area-linkAge': areaLinkAge,
},
data() {
return {
// !!! 回显的属性后面有Code
editAreaParams: {
provinceCode: '',
cityCode: '',
areaCode: '',
},
addrVisible:false
}
},
methods: {
// 获取子组件选择区域后的数据 - 地址code
getAreaParam(val){
this.editAreaParams.province = val.province;
this.editAreaParams.city = val.city;
this.editAreaParams.area = val.area;
},
// 获取子组件选择区域后的数据 - 地址Text
getAreaParam(val){
this.editAreaParams.provinceText = val.provinceText;
this.editAreaParams.cityText = val.cityText;
this.editAreaParams.areaText = val.areaText;
},
//xhr - 回显详情
xhrDisplayInfo(){
let param = {
id: this.orderId
}
getDetailInsMerchant(param).then(res=>{
if(res.statusCode === HTTP_CODE.suc){
this.editAreaParams = res.data.address; // "北京市-北京市-朝阳区"
// this.editAreaParams.provinceCode = this.addInsMerchantParams.province;
// this.editAreaParams.cityCode = this.addInsMerchantParams.city;
// this.editAreaParams.areaCode = this.addInsMerchantParams.area;
}
})
},
}
好了~ 如果走到这一步就成功了。恭喜💐
再见~ 江湖再见!
来源:oschina
链接:https://my.oschina.net/wsxiao/blog/4296030