基于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>
相关推荐
待磨的钝刨8 分钟前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
逐·風3 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫4 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦4 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子5 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享6 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
程序媛小果6 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
从兄6 小时前
vue 使用docx-preview 预览替换文档内的特定变量
javascript·vue.js·ecmascript
凉辰7 小时前
设计模式 策略模式 场景Vue (技术提升)
vue.js·设计模式·策略模式