VUE与NUXT3通用省市区地址三级联动选择组件。
发布于2023-10-17 15:40 阅读810次 NUXT3与VUE通用省市区地址三级联动选择组件,组件使用了VUE3的Setup语法糖,由于地址太多发布不全,这里只提供了几个典型的省市区模板参考,其它省市区还得自己去补齐。街道门牌号必须大于5个字符才会正
常返回地址内容给父级组件,同时支持父级组件回传地址并自动识别省份、城市、区县并自动处于选取状态,可以更好的提供地址修改时回传识别。
街道门牌号使用flex弹性布局,联动选择时剩余可以宽度小于80像素时会自动换行并调整宽带为100%,可以更好适应各种不同场景和显示设备宽度。
组件使用了tailwindcss,如需要其它三方或原生CSS,需要自行修改。
VUE3下直接在components文件夹下建立文件addressPick.vue并复制以下代码即可,Nuxt3下在components新建 addressPick.client.vue即可使用。
调用:
代码:
```
<script setup>
const list = ref([
{
"sf":"北京市",
"cs":["东城区","西城区","朝阳区","丰台区","石景山区","海淀区","门头沟区","房山区","通州区","顺义区","昌平区","大兴区","怀柔区","平谷区","密云区","延庆区"]
},
{
"sf":"天津市",
"cs":["和平区","河东区","河西区","南开区","河北区","红桥区","东丽区","西青区","津南区","北辰区","武清区","宝坻区","滨海新区","宁河区","静海区","蓟州区"]
},
{
"sf":"海南省",
"cs":[
{
"cs":"海口市",
"qy":["秀英区","龙华区","琼山区","美兰区"]
},
{
"cs":"三亚市",
"qy":["海棠区","吉阳区","天涯区","崖州区"]
},
{
"cs":"三沙市",
"qy":["市区"]
},
{
"cs":"儋州市",
"qy":["市区"]
},
{
"cs":"省直辖县级行政区划",
"qy":["五指山市","琼海市","文昌市","万宁市","东方市","定安县","屯昌县","澄迈县","临高县","白沙黎族自治县","昌江黎族自治县","乐东黎族自治县","陵水黎族自治县","保亭黎族苗族自治县","琼中黎族苗族自治县"]
}
]
},
{
"sf":"台湾省",
},
{
"sf":"香港特别行政区",
},
{
"sf":"澳门特别行政区",
}
]);
//组件通信
const props=defineProps({
modelValue:{type:String,require:false,default:''},
});
const emits=defineEmits(['update:modelValue']);
//定义变量
const sf=ref(''),cs=ref(''),cstmp=ref([]),qy=ref(''),qytmp=ref([]),detail=ref(''),addressTmp=ref(props.modelValue),
address=computed(()=>{
if(!sf.value||(cstmp.value.length>0&&!cs.value)||(qytmp.value.length>0&&!qy.value)||detail.value.length<5)
return '';
else
return sf.value+cs.value+qy.value+detail.value;
});
//钩子函数
watch(()=>address.value,()=>{
emits('update:modelValue',address.value);
});
onMounted(()=>{
if(addressTmp.value){
emits('update:modelValue','');//加载后如果带有地址则清空以便以正常地址返回为空,再重新计算
try{
list.value.forEach((key,index,map)=>{
if(addressTmp.value.indexOf(key.sf)==0){
addressTmp.value=addressTmp.value.replace(key.sf,'');
sf.value=key.sf;
sfchange();
if(cstmp.value.length>0){
var tmpcs='';
cstmp.value.forEach((key,index,map)=>{
if(typeof key=='string')
tmpcs=key;
else
tmpcs=key.cs;
if(addressTmp.value.indexOf(tmpcs)==0){
addressTmp.value=addressTmp.value.replace(tmpcs,'');
cs.value=tmpcs;
cschange();
if(qytmp.value.length>0){
qytmp.value[0].qy.forEach((key,index,map)=>{
if(addressTmp.value.indexOf(key)==0){
addressTmp.value=addressTmp.value.replace(key,'');
qy.value=key;
throw false;
}
});
}
throw false;
}
});
};
throw false;
}
});
}catch(e){};
detail.value=addressTmp.value;
}
});
//定义方法
const sfchange=()=>{
var tmp=list.value.filter(item=>item.sf==sf.value);
if(tmp.length>0&&tmp[0].cs)
cstmp.value=tmp[0].cs;
else
cstmp.value=[];
qytmp.value=[];
cs.value='';
qy.value='';
};
const cschange=()=>{
if(cstmp.value.length>0&&cstmp.value[0].cs) qytmp.value=cstmp.value.filter(item=>item.cs==cs.value);
qy.value='';
};
</script>
<template>
<div class="flex flex-wrap">
<select v-model="sf" @change="sfchange" class="text-center rounded p-1 m-px ml-0">
<option value="" disabled>省/市</option>
<option v-for="item in list" :key="item" :value="item.sf">{{item.sf}}</option>
</select>
<select v-model="cs" @change="cschange" v-if="cstmp.length>0" class="text-center rounded p-1 m-px">
<option value="" disabled>市/区</option>
<option v-for="item in cstmp" :key="item" :value="item.cs?item.cs:item">{{item.cs?item.cs:item}}</option>
</select>
<select v-model="qy" v-if="qytmp.length>0" class="text-center rounded p-1 m-px">
<option value="" disabled>区/县</option>
<option v-for="item in qytmp[0].qy" :key="item" :value="item">{{item}}</option>
</select>
<input type="text" v-model="detail" class="flex-auto w-auto rounded border outline-none my-px p-0.5" placeholder="街道及门牌" style="min-width:100px"/>
</div>
</template>
```