1. 效果
是骡子是马先拉出来溜溜,我们先看效果:
2.实现思路
1. 获取四级联动的数据文件
首先这个数据必须是经过国家统计局、民政部认证的,不能瞎编乱造,然后数据格式一般是 json 格式。
中国省市区街道json文件下载地址:
bash
链接:https://pan.baidu.com/s/1giYramKo5c6R1gIgOouScw?pwd=6cjp
提取码:6cjp
2. 数据联动
我们发现这个地址数据格式的特点:只有最里层街道数据是数组,然后外三层都是对象。
那我们首先想到 Object.keys() 方法可以获取所有对象属性的键名(key),也就是最外层的省份数据。
css
// 省列表
const provinceList = Object.keys(areaData);
接着我们通过 computed 计算属性进行数据的联动
拿到省份数据之后,我们选择某一个省份,我们就可以通过 areaData[选择的省份] 获取这个省份对应的属性值,然后再用 Object.keys(areaData[选择的省份]) 获取该省份下面所有的市数据。
css
import areaData from "../../../assets/json/area.json";
// 市列表
const cityList = computed(() => {
return area.province ? Object.keys(areaData[area.province]) : [];
});
Object.keys(areaData[选择的省份][选择的市])就是该市下面所有的县区数据
css
// 县区列表
const districtList = computed(() => {
return area.province && area.city
? Object.keys(areaData[area.province][area.city])
: [];
});
areaData[选择的省份][选择的市][选择的县区]就是该县区下面所有的街道数据
css
// 街道列表
const streetList = computed(() => {
return area.province && area.city && area.district
? areaData[area.province][area.city][area.district]
: [];
});
3. 清除关联数据
- 选择另外一个省份,清除之前的市区街道数据
- 选择另外的市,清除县区街道数据
- 选择另外的县区,清除街道数据
这里,我们通过 watch 来监听省份、市、县区的变化
css
// 监听省份变化
watch(
() => area.province,
(newVal) => {
area.city = "";
area.district = "";
area.street = "";
}
);
// 监听市区变化
watch(
() => area.city,
(newVal) => {
area.district = "";
area.street = "";
}
);
// 监听县区变化
watch(
() => area.district,
(newVal) => {
area.street = "";
}
);
3.完整代码
css
<template>
<div>
<el-card class="box-card" style="width: 50%; margin: 20px">
<template #header>
<div class="card-header">
<span>中国省市区街道四级联动</span>
</div>
</template>
<el-form
class="area"
ref="areaForm"
:model="area"
:rules="rules"
label-width="100px"
size="large"
>
<el-form-item label="省:" prop="province">
<el-select
style="width: 100%"
v-model="area.province"
filterable
clearable
placeholder="请选择省份"
>
<el-option
v-for="item in provinceList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="市:" prop="city">
<el-select
style="width: 100%"
v-model="area.city"
filterable
clearable
placeholder="请选择市"
>
<el-option v-for="item in cityList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item label="县区:" prop="district">
<el-select
style="width: 100%"
v-model="area.district"
filterable
clearable
placeholder="请选择县区"
>
<el-option
v-for="item in districtList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="街道:" prop="street">
<el-select
style="width: 100%"
v-model="area.street"
filterable
clearable
placeholder="请选择街道"
>
<el-option
v-for="item in streetList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button size="mini" type="primary" @click="onSubmit">提交</el-button>
<el-button size="mini">公众号:知否技术</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script setup>
import { reactive, computed, watch } from "vue";
import areaData from "./assets/json/area.json";
const area = reactive({
province: "",
city: "",
district: "",
street: "",
});
//------省市县区街道四级联动
// 省列表
const provinceList = Object.keys(areaData);
// 市列表
const cityList = computed(() => {
return area.province ? Object.keys(areaData[area.province]) : [];
});
// 县区列表
const districtList = computed(() => {
return area.province && area.city
? Object.keys(areaData[area.province][area.city])
: [];
});
// 街道列表
const streetList = computed(() => {
return area.province && area.city && area.district
? areaData[area.province][area.city][area.district]
: [];
});
// 监听省份变化
watch(
() => area.province,
(newVal) => {
area.city = "";
area.district = "";
area.street = "";
}
);
// 监听市区变化
watch(
() => area.city,
(newVal) => {
area.district = "";
area.street = "";
}
);
// 监听县区变化
watch(
() => area.district,
(newVal) => {
area.street = "";
}
);
</script>