Vue3 + Element Plus 省市区县级联cascader组件封装,支持 v-model 双向绑定 + 回显,可直接复用

在后台管理系统中,省市区三级联动是非常常见的需求,无论是查询条件、新增表单、编辑弹窗,都需要用到。

为了避免重复代码,提升开发效率,我们可以把省市区三级联动封装成一个通用复用组件,支持:

  • 三级联动
  • v-model 双向绑定
  • 数据回显(编辑页面必备)
  • 清空、禁用联动
  • 多页面复用

之前我们用了三个下拉select来实现➡️:Vue3 + Element Plus 省市区县级联下拉select组件封装

本文以同样的实现思路,用el-cascader来一步一步实现。即:由3 个 select变为1个个 cascader


全部代码⬇️

javascript 复制代码
<template>
  <div class="region-picker">
    <el-cascader
      v-model="selectedIds"
      :options="provinceList"
      placeholder="请选择省/市/区"
      clearable
      style="width: 100%"
      @change="handleChange"
    />
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'

// 模拟省市区数据(和你原来一样)
const regionData = [
  {
    value: '110000',
    label: '北京市',
    children: [
      {
        value: '110100',
        label: '北京市',
        children: [
          { value: '110101', label: '东城区' },
          { value: '110102', label: '西城区' },
          { value: '110105', label: '朝阳区' },
          { value: '110106', label: '丰台区' },
          { value: '110108', label: '海淀区' },
        ]
      }
    ]
  },
  {
    value: '410000',
    label: '河南省',
    children: [
      {
        value: '410100',
        label: '郑州市',
        children: [
          { value: '410102', label: '中原区' },
          { value: '410103', label: '二七区' },
          { value: '410104', label: '管城回族区' },
          { value: '410105', label: '金水区' },
        ]
      },
      {
        value: '410300',
        label: '洛阳市',
        children: [
          { value: '410302', label: '老城区' },
          { value: '410303', label: '西工区' },
        ]
      }
    ]
  }
]

// 类型定义
interface RegionModel {
  provinceId: string
  cityId: string
  districtId: string
}

// Props
const props = withDefaults(defineProps<{
  modelValue?: RegionModel
}>(), {
  modelValue: () => ({ provinceId: '', cityId: '', districtId: '' })
})

const emit = defineEmits<{
  'update:modelValue': [value: RegionModel]
  'change': [value: RegionModel]
}>()

// cascader 绑定值是数组 [省id, 市id, 区id]
const selectedIds = ref<string[]>([])

// 选项
const provinceList = computed(() => regionData || [])

// 外部 modelValue 同步进来(编辑回显)
watch(
  () => props.modelValue,
  (val) => {
    if (val) {
      selectedIds.value = [
        val.provinceId || '',
        val.cityId || '',
        val.districtId || ''
      ].filter(Boolean)
    }
  },
  { deep: true, immediate: true }
)

// 内部选择变化 → 抛给父组件
const handleChange = (ids: string[]) => {
  const value = {
    provinceId: ids[0] || '',
    cityId: ids[1] || '',
    districtId: ids[2] || ''
  }
  emit('update:modelValue', value)
  emit('change', value)
}
</script>

<style scoped>
.region-picker {
  width: 100%;
}
</style>

任意页面调用⬇️

javascript 复制代码
<RegionPicker v-model="form.region" />

如果需要赋默认值(如编辑弹窗)⬇️

javascript 复制代码
const form = ref({
  region: {
    provinceId: '410000',
    cityId: '410100',
    districtId: '410105'
  }
})

如有疑问,欢迎评论区友好讨论😊

相关推荐
菜鸟茜2 个月前
Vue3 + Element Plus 省市区县级联组件封装,支持 v-model 双向绑定 + 回显,可直接复用
vue3·element-plus·组件封装·前端复用·省市区县级联
赢乐2 个月前
前端vue表格el-table或a-table合并行的功能实现
elementui·el-table·element-plus·anti-design-vue·a-table·vue前端·表格合并行
蜗牛攻城狮2 个月前
【Vue3实战】El-Table实现“超过3行省略,悬停显示全文”的完美方案(附性能优化)
前端·vue.js·性能优化·element-plus
浩宇软件开发3 个月前
springBoot+Vue中华诗词学习后台管理系统
vue.js·spring boot·axios·element-plus·router
利刃大大4 个月前
【Vue】Element-Plus快速入门 && Form && Card && Table && Tree && Dialog && Menu
前端·javascript·vue.js·element-plus
程序员张34 个月前
Element Plus SCSS 变量覆盖用法
vue.js·前端框架·element-plus
益达是我7 个月前
【element-plus】element-plus升级到v2.11.7,el-tree文字不显示问题
前端·javascript·vue.js·element-plus
ejinxian7 个月前
2025 Vue UI 组件库选型
element-plus·ant-design-vue·arco-design·tdesign-vuenext
williamdsy9 个月前
【Element-Plus】媒体预览模态框优化实战:从复杂到简洁的设计之路
vue·媒体·element-plus