要啥插件!vue3手写省市区街道四级联动!

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>
相关推荐
KaMeidebaby14 小时前
卡梅德生物技术快报|蛋白 N 端测序在重组贻贝融合蛋白表征中的应用,解决原核表达序列偏移工艺难题
前端·人工智能·物联网·算法·百度
kyriewen15 小时前
我筛了 1400 个 Claude Code Skills,留下 5 个天天在用的
前端·ai编程·claude
JNX_SEMI15 小时前
AT2401C 2.4GHz 全集成射频前端单芯片技术解析
前端·单片机·嵌入式硬件·物联网·硬件工程
anOnion16 小时前
Agentic 前端开发之 实时显示 AI Agent 终端输出
前端·javascript·人工智能
随风一样自由16 小时前
【前端领域】2026最新前端领域全梳理(框架/工具/AI/跨端/底层标准/就业趋势)
前端·人工智能·前端框架
这是个栗子16 小时前
【前端性能优化】优化数据加载:用 Promise.all 从串行到并行
前端·javascript·性能优化·异步编程·前端优化·promise.all
fei_sun16 小时前
黑洞路由(Null Route/空接口路由)
服务器·前端·javascript
大爱一家盟17 小时前
告别卡点BGM同质化 2026原创卡点音乐素材下载网站 TOP5 推荐
大数据·前端·人工智能
彦为君17 小时前
算法思维与经典智力题
java·前端·redis·算法
aa小小17 小时前
localhost 访问异常排查笔记
前端