基于ElementUI封装省市区四级联动下拉选择

基于ElementUI封装的省市区下拉级联选择

效果

数据

最新省市区JSON数据获取:https://xiangyuecn.github.io/AreaCity-JsSpider-StatsGov/

参数说明

参数 说明
inputNumShow 下拉框的数量,最多4个
defaultAddress 默认显示省市区 例:['安徽', '阜阳', '颍上', '十八里铺']
inputInterval 选择框间的间距

组件代码

javascript 复制代码
<template>
  <div>
    所在地区:
    <el-select v-show="inputNumShow>=1" v-model="provinceData" clearable @change="provinceChange" filterable placeholder="请选择省">
      <el-option v-for="item in provinceDataOpt" :key="item.n" :label="item.n" :value="item.n"></el-option>
    </el-select>
    <el-select :style="{marginLeft:inputInterval+'px'}" v-show="inputNumShow>=2" clearable no-data-text="请选择上级" v-model="cityData" @change="cityChange"
      filterable placeholder="请选择市">
      <el-option v-for="item in cityDataOpt" :key="item.n" :label="item.n" :value="item.n"></el-option>
    </el-select>
    <el-select :style="{marginLeft:inputInterval+'px'}" v-show="inputNumShow>=3" clearable no-data-text="请选择上级" @change="areaChange" v-model="areaData"
      filterable placeholder="请选择区县">
      <el-option v-for="item in areaDataOpt" :key="item.n" :label="item.n" :value="item.n"></el-option>
    </el-select>
    <el-select :style="{marginLeft:inputInterval+'px'}"  @change="streetChange" v-show="inputNumShow>=4"  clearable no-data-text="请选择上级" v-model="streetData"
      filterable placeholder="请选择城镇村">
      <el-option v-for="item in streetDataOpt" :key="item.n" :label="item.n" :value="item.n"></el-option>
    </el-select>
  </div>
</template>
<script>
/**
 * addressData为省市区的数据,获取地址为:https://xiangyuecn.github.io/AreaCity-JsSpider-StatsGov/
 * addressData参数说明:
 *    n:名称
 *    y:名称前缀
 *    c:子集
 */
import addressData from "./address.json"; //全国省市区街道数据
export default {
  name: "hsk-addressSel",
  props:{
    inputNumShow:{
      type:Number,
      default:4,
    },
    inputInterval:{
      type:Number,
      default:10
    },
    defaultAddress:{
      type:Array,
      default(){
        return []
      }
    }
  },
  data() {
    return {
      provinceData: undefined,
      cityData: undefined,
      areaData: undefined,
      streetData: undefined,
      provinceDataOpt: [],//  省,自治区,直辖市,特别行政区都在其中
      cityDataOpt: [], //  市数据
      areaDataOpt: [],// 区数据
      streetDataOpt: [], //城镇
      sourceData: null,
    }
  },
  created() {
    //省市区镇数据处理,将省市区镇数据分离出来
    this.dataProces()
 
  },
  mounted(){
    //可能是省市区,也可能是省市,也可能是省市县镇
    if(typeof(this.defaultAddress[0]) !== "undefined"){
      this.provinceData = this.defaultAddress[0]
      this.provinceChange( this.defaultAddress[0])
    }
    if(typeof(this.defaultAddress[1]) !== "undefined"){
      this.cityData = this.defaultAddress[1]
      this.cityChange(this.defaultAddress[1])
    }
    if(typeof(this.defaultAddress[2]) !== "undefined"){
      this.areaData = this.defaultAddress[2]
      this.areaChange(this.defaultAddress[2])
    }
    if(typeof(this.defaultAddress[3]) !== "undefined"){
      this.streetData = this.defaultAddress[3]
      this.streetChange(this.defaultAddress[3])
    }
    
  },
  methods: {
    //数据初始化处理
    dataProces() {
      //初始化
      this.provinceDataOpt = []
      this.cityDataOpt = []
      this.areaDataOpt = []
      this.streetDataOpt = []
      this.sourceData = undefined
      this.cityData = undefined
      this.areaData = undefined
      this.streetData = undefined
      this.sourceData = addressData
      //递归,为每层添加level,区分省,市,县,镇,并将数据放入指定变量中使用
      this.addLevel(this.sourceData)
    },
    /**
     * 递归为每个层级添加一个level
     * 0.(省,自治区,直辖市,特别行政区)、
     * 1.(市,直辖市,特别行政区)、
     * 2.(区,县,镇)、
     * 3. (城,镇,街道)、
     * 将省市区城镇放入到指定的provinceData,cityData,areaData,streetData
     */
    addLevel(data, level = 0) {
      for (const key in data) {
        if (typeof data[key] === 'object' && !Array.isArray(data[key])) {
          data[key].level = level;
          if (level === 0) {
            this.provinceDataOpt.push(data[key])
          }
          if ('c' in data[key]) {
            this.addLevel(data[key].c, level + 1);
          }
        }
      }
    },
    /**
     * 当省份改变选中时触发,获取市,直辖市,行政区,自治区
     */
    provinceChange(e) {
      this.cityDataOpt = []
      this.cityData = undefined      
      this.areaData = undefined
      this.areaDataOpt = []
      this.streetData = undefined
      this.streetDataOpt = []
      //根据选中项确定市,直辖市,或者特别行政区的数据
      for (let i = 0; i < this.provinceDataOpt.length; i++) {
        if (e === this.provinceDataOpt[i].n) {
          //获取市的内容放入市区数组
          for (let j in this.provinceDataOpt[i].c) {
            //获取市,直辖市,行政区,自治区        
            this.cityDataOpt.push(this.provinceDataOpt[i].c[j])
          }
        }
      }      
      this.$emit("addressChange",[this.provinceData])
    },
    /**
     * 当市区修改的时候触发,获取县,区
     */
    cityChange(e) {
      this.areaData = undefined
      this.areaDataOpt = []
      this.streetData = undefined
      this.streetDataOpt = []
      // 拿到县区选项
      for (let i = 0; i < this.cityDataOpt.length; i++) {
        if (e === this.cityDataOpt[i].n) {
          for (let j in this.cityDataOpt[i].c) {
            this.areaDataOpt.push(this.cityDataOpt[i].c[j])
          }
        }
      }
      this.$emit("addressChange",[this.provinceData,this.cityData])
    },
    /**
     * 当前区县修改时触发,获取城镇选项列表
     */
    areaChange(e) {
      this.streetData = undefined
      this.streetDataOpt = []
       // 拿到城镇庄村选项
       for (let i = 0; i < this.areaDataOpt.length; i++) {
        if (e === this.areaDataOpt[i].n) {
          for (let j in this.areaDataOpt[i].c) {
            this.streetDataOpt.push(this.areaDataOpt[i].c[j])
          }
        }
      }
      this.$emit("addressChange",[this.provinceData,this.cityData,this.areaData])
    },
    streetChange(e){
      this.$emit("addressChange",[this.provinceData,this.cityData,this.areaData,e])
    }
  }
  
}
</script>

<style></style>

父组件使用

javascript 复制代码
<template>
  <div>
    <el-button type="primary" size="mini" @click="xzjiajia">选择++</el-button>
    <el-button type="primary" size="mini" @click="xzjianjian">选择--</el-button>
    <el-button type="primary" size="mini" @click="jjjiajia">间距++</el-button>
    <el-button type="primary" size="mini" @click="jjjianjian">间距--</el-button>
   <div style="margin-top: 20px;">
    <hsk-address-sel :inputNumShow="inputNumShow" :inputInterval="inputInterval" @addressChange="addressChange"
      :defaultAddress="['安徽', '阜阳', '颍上', '十八里铺']" />
   </div>
  </div>
</template>

<script>
import HskAddressSel from '../package/hsk-addressSel/index.vue'
export default {
  name: "hskAddressSelPage",
  components: {
    HskAddressSel
  },
  data() {
    return {
      inputNumShow: 4,
      inputInterval: 10,
    }
  },
  methods: {
    xzjiajia() {
      this.inputNumShow++
    },
    xzjianjian() {
      this.inputNumShow--
    },
    jjjiajia() {
      this.inputInterval++
    },
    jjjianjian() {
      this.inputInterval--
    },
    addressChange(e){
      console.log("地址:",e)
    }
  }
}
</script>
<style></style>
相关推荐
h***34634 分钟前
SpringBoot3.3.0集成Knife4j4.5.0实战
android·前端·后端
Yanni4Night4 分钟前
数据可视化神器Heat.js:让你的数据热起来
前端·javascript
Lazy_zheng4 分钟前
前端页面更新检测实战:一次关于「用户不刷新」的需求拉扯战
前端·vue.js·性能优化
前端一课7 分钟前
【vue高频面试题】第9题:Vue3 的响应式原理是什么?和 Vue2 的响应式有什么区别?为什么 Vue3 改用了 Proxy?
前端·面试
Demon--hx8 分钟前
[C++]迭代器失效问题
前端·c++
GISer_Jing9 分钟前
前端架构学习
前端·学习·架构
前端一课9 分钟前
【vue高频面试题】第4题:Vue 3 中的 setup() 是什么?它的执行时机是什么?能做什么?
前端·面试
前端一课10 分钟前
【vue高频面试题】第5题:Vue3 的父子组件通信方式有哪些?分别适用于什么场景?
前端·面试
Funny Valentine-js11 分钟前
web实验后端php测试文本
前端·javascript·php·html5·cookie·telnet·session
前端一课14 分钟前
【vue高频面试题】第6题:Vue3 中 Composition API 和 Options API 有什么区别?为什么 Composition API 更推荐
前端·面试