老师,你好
如何使用v-modal,双向绑定省市区选择器?
下面代码虽然能实现此功能,但感觉不太优雅,要使用 setTimeout + watch 去一级一级的控制下拉框列表数据的渲染,请问老师有更好的方法、思路吗?多谢多谢~~
<template>
<div class="area-choose jiang-select-margin">
<el-select v-model="province" placeholder="请选择省份" clearable>
<el-option
v-for="item in provinceList"
:key="item.code"
:value="item.code"
:label="item.name"
>
</el-option>
</el-select>
<el-select
v-model="city"
placeholder="请选择城市"
:disabled="!province"
clearable
>
<el-option
v-for="item in cityList"
:key="item.code"
:value="item.code"
:label="item.name"
></el-option>
</el-select>
<el-select
v-model="area"
placeholder="请选择区域"
:disabled="!province || !city"
clearable
>
<el-option
v-for="item in areaList"
:key="item.code"
:value="item.code"
:label="item.name"
>
</el-option>
</el-select>
<el-select
v-model="street"
placeholder="请选择街道"
:disabled="!province || !city || !area"
clearable
>
<el-option
v-for="item in streetList"
:key="item.code"
:value="item.code"
:label="item.name"
>
</el-option>
</el-select>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, watch, PropType } from "vue";
import pacsCode from "china-division/dist/pcas-code.json";
export interface AreaItem {
name: string;
code: string;
children?: AreaItem[];
}
export interface addressProps {
province: AreaItem;
city: AreaItem;
area: AreaItem;
street: AreaItem;
}
export default defineComponent({
name: "area-choose",
emits: ["update:address"],
props: {
address: {
type: Object as PropType<addressProps>,
required: true,
},
},
setup(props, { emit }) {
const provinceList = ref(pacsCode);
const province = ref("");
const city = ref("");
const area = ref("");
const street = ref("");
const cityList = ref<AreaItem[]>([]);
const areaList = ref<AreaItem[]>([]);
const streetList = ref<AreaItem[]>([]);
watch(
() => props.address,
async (val) => {
if (val) {
province.value = props.address?.province.code;
setTimeout(() => {
city.value = props.address.city.code;
}, 0);
setTimeout(() => {
area.value = props.address.area.code;
}, 0);
setTimeout(() => {
street.value = props.address.street.code;
}, 0);
}
},
{
immediate: true,
}
);
watch(
() => province.value,
(val) => {
if (val) {
let cities = provinceList.value.find(
(item) => item.code === val
)?.children;
if (cities) {
cityList.value = cities;
}
}
city.value = "";
area.value = "";
street.value = "";
},
{
immediate: true,
}
);
watch(
() => city.value,
(val) => {
console.log("city.value", val);
if (val) {
let areas = cityList.value.find(
(item) => item.code === val
)?.children;
if (areas) {
areaList.value = areas;
}
}
area.value = "";
street.value = "";
},
{
immediate: true,
}
);
watch(
() => area.value,
(val) => {
if (val) {
let streets = areaList.value.find(
(item) => item.code === val
)?.children;
if (streets) {
console.log(streets);
streetList.value = streets;
}
}
street.value = "";
},
{
immediate: true,
}
);
watch(
() => street.value,
(val) => {
console.log(val);
if (val) {
let selectedProvince = {
code: province.value,
name: provinceList.value.find(
(item) => item.code === province.value
)?.name,
};
let selectedCity = {
code: city.value,
name: cityList.value.find((item) => item.code === city.value)?.name,
};
let selectedArea = {
code: area.value,
name: areaList.value.find((item) => item.code === area.value)?.name,
};
let selectedStreet = {
code: val,
name: streetList.value.find((item) => item.code === val)?.name,
};
emit("update:address", {
province: selectedProvince,
city: selectedCity,
area: selectedArea,
street: selectedStreet,
});
}
}
);
return {
province,
city,
area,
street,
provinceList,
cityList,
areaList,
streetList,
};
},
});
</script>
<style scoped lang="less"></style>