153 lines
3.6 KiB
Vue

<template>
<div class="areabox">
<el-select
v-model="address.province"
placeholder="请选择省"
:style="{ width: `${prop.width}px`, marginRight: `${prop.gap}px` }"
@change="handleProvinceSelect"
>
<el-option v-for="item in regionData" :label="item.label" :value="item.value" />
</el-select>
<el-select
v-model="address.city"
placeholder="请选择市"
:disabled="!address.province || cityList.length == 0"
:style="{ width: `${prop.width}px`, marginRight: `${prop.gap}px` }"
@change="handleCitySelect"
>
<el-option v-for="item in cityList" :label="item.label" :value="item.value" />
</el-select>
<el-select
v-model="address.area"
placeholder="请选择区"
:style="{ width: `${prop.width}px` }"
:disabled="!address.province || !address.city || areaList.length == 0"
@change="handleAreaSelect"
>
<el-option v-for="item in areaList" :label="item.label" :value="item.value" />
</el-select>
</div>
</template>
<script lang="ts" setup>
import { reactive, computed, ComputedRef, watch } from "vue";
import { regionData, CodeToText } from "element-china-area-data";
import { add } from "lodash";
const prop = withDefaults(
defineProps<{
modelValue?: {
province: string | undefined;
city: string | undefined;
district: string | undefined;
};
gap?: string | number; //选择框中间间隙
width?: string | number; //选择框宽度
}>(),
{
gap: "8",
width: "210"
}
);
//抛出地址
const emit = defineEmits<{
(
e: "getAddress",
data: {
code: string[]; //区域码
name: string[]; //汉字
isComplete: boolean; //是否选择完整,方便校验
}
): void;
}>();
let address = reactive<{
province: string;
city: string;
area: string;
}>({
province: "",
city: "",
area: ""
});
watch(
() => prop.modelValue,
() => {
address.province = prop.modelValue?.province;
address.city = prop.modelValue?.city;
address.area = prop.modelValue?.district;
},
{
immediate: true
}
);
interface AreaList {
value: string;
label: string;
children?: AreaList[];
}
//切换省份函数
const handleProvinceSelect = () => {
address.city = "";
address.area = "";
emit("getAddress", {
code: [address.province], //区域码
name: [CodeToText[address.province]], //汉字
isComplete: false
});
};
//切换城市函数
const handleCitySelect = () => {
address.area = "";
emit("getAddress", {
code: [address.province, address.city], //区域码
name: [CodeToText[address.province], CodeToText[address.city]], //汉字
isComplete: areaList.value.length == 0 ? true : false
});
};
//切换地区函数
const handleAreaSelect = () => {
emit("getAddress", {
code: [address.province, address.city, address.area], //区域码
name: [CodeToText[address.province], CodeToText[address.city], CodeToText[address.area]], //汉字
isComplete: true
});
};
//二级城市列表
const cityList: ComputedRef<AreaList[]> = computed((): AreaList[] => {
if (!address.province) {
return [];
}
let temp = regionData.find((item: any) => {
return item.value == address.province || item.label == address.province;
});
if (!temp) return;
return temp.children ? temp.children : [];
});
//三级地区列表
const areaList: ComputedRef<AreaList[]> = computed((): AreaList[] => {
if (!address.province || !address.city) {
return [];
}
if (cityList.value.length == 0) {
return [];
} else {
let temp = cityList.value.find((item: any) => {
return item.value == address.city || item.label == address.city;
});
if (temp) {
return temp.children ? temp.children : [];
} else {
return [];
}
}
});
</script>
<style lang="scss" scoped>
.areabox {
display: flex;
align-items: center;
}
</style>