基于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>
相关推荐
无责任此方_修行中21 分钟前
每周见闻分享:杂谈AI取代程序员
javascript·资讯
Σίσυφος19001 小时前
halcon 条形码、二维码识别、opencv识别
前端·数据库
学代码的小前端1 小时前
0基础学前端-----CSS DAY13
前端·css
dorabighead2 小时前
JavaScript 高级程序设计 读书笔记(第三章)
开发语言·javascript·ecmascript
css趣多多2 小时前
案例自定义tabBar
前端
姑苏洛言3 小时前
DeepSeek写微信转盘小程序需求文档,这不比产品经理强?
前端
林的快手3 小时前
CSS列表属性
前端·javascript·css·ajax·firefox·html5·safari
匹马夕阳4 小时前
ECharts极简入门
前端·信息可视化·echarts
bug总结4 小时前
新学一个JavaScript 的 classList API
开发语言·javascript·ecmascript
网络安全-老纪4 小时前
网络安全-js安全知识点与XSS常用payloads
javascript·安全·web安全