Vue 含有"不限"的省市区三级联动的组件

Posted 1994july

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue 含有"不限"的省市区三级联动的组件相关的知识,希望对你有一定的参考价值。

工作中会经常会遇到选择省市区三级联动的需求,每次都有不同的需求,比如有不限,比如动态添加多个,比如宽度自定义,比如回显,回显类型不确定。。。等等。。。

每次都要根据需求定制,现在闲下来,将这些暂时遇到的需求整合到了一个组件里面,希望可以暂时救一下在花样需求的沼泽里出不来的人。

个人写的,肯定有可优化的地方,肯定有覆盖不到的地方。请见谅~,欢迎留下你的只言片语,足够我醍醐灌顶~~(不会成语的author,不是一个号前端)

支持一下需求:

  • 基于element-ui写的,可自行更换或者用原生;
  • 省市区三级,暂时不支持四级;
  • 省市区列表是否包含"不限",可自行从父组件传参,参数:unlimit,取值:true - 有不限,false - 无不限
  • 宽度自定义,可自行从父组件传参,参数:pWidth:省宽度,cWidth:市宽度,aWidth:区宽度
  • 支持添加多个,如需记录index,传参:fatherIndex
  • 地址map前端写死,如有改动,自行改动。

一、引入地址map依赖文件:map.js

地址:https://my.oschina.net/wsxiao/blog/4295971

二、地址选择下拉框子组件

<!--
  @Author: DKing
  @Desc: 三级联动
  @Date: 2020-04-30
-->

<template>
  <div>
    <el-select
      v-model="areaParams.provinceCode"
      @change="choseProvince"
      clearable
      placeholder="请选择"
      class=‘el-select-adress el-select-adress-p‘
    >
      <el-option
        v-for="item in defaultProvince"
        :key="item.id"
        :label="item.value"
        :value="item.id">
      </el-option>
    </el-select>


    <el-select
      v-model="areaParams.cityCode"
      clearable @change="choseCity"
      placeholder="请选择"
      class=‘el-select-adress el-select-adress-c‘
    >
      <el-option
        v-for="item in cityArray"
        :key="item.id"
        :label="item.value"
        :value="item.id">
      </el-option>
    </el-select>


    <el-select
      v-model="areaParams.areaCode"
      clearable @change="choseBlock"
      placeholder="请选择"
      class=‘el-select-adress el-select-adress-a‘
    >
      <el-option
        v-for="item in areaArray"
        :key="item.id"
        :label="item.value"
        :value="item.id">
      </el-option>
    </el-select>
  </div>
</template>

<script>
import {AREA} from "../filters/map";
import {checkNull} from "../filters/filters";
import Vue from ‘vue‘

export default {
  props:{
    // 回显参数
    editAreaParams: null,

    // 省下拉框的宽度
    pWidth:{
      type: String,
    },
    // 市下拉框的宽度
    cWidth:{
      type: String,
    },
    // 区下拉框的宽度
    aWidth:{
      type: String,
    },
    // 父组件的index 适用于添加过个地址
    fatherIndex:{
      type: Number
    },
    // 是否有 不限 true:有,false:无
    unlimit:{
      type: Boolean || String,
      default: false
    }
  },

  data () {
    return {
      mapJson: AREA,

      defaultProvince: [],
      defaultCity: [],
      defaultArea: [],
      cityArray: [],
      areaArray: [],

      editAreaParamsTemp: this.editAreaParams,
      unlimitTemp: this.unlimit == true || this.unlimit == ‘true‘,

      areaParams: {
        provinceCode: ‘‘,
        cityCode: ‘‘,
        areaCode: ‘‘
      },

      queryParam:{
        province: ‘‘,
        city: ‘‘,
        area: ‘‘
      } ,//给父传递参数

      queryParamText:{
        province: ‘‘,
        city: ‘‘,
        area: ‘‘
      }

    }
  },

  created(){
    // 宽度自定义
    this.$nextTick(() =>{
      let pDom = document.getElementsByClassName(‘el-select-adress-p‘) || []
      let cDom = document.getElementsByClassName(‘el-select-adress-c‘) || []
      let aDom = document.getElementsByClassName(‘el-select-adress-a‘) || []
      for(let p of pDom){
        p.children[0].style.width = this.pWidth
      }

      for(let c of cDom){
        c.children[0].style.width = this.cWidth
      }

      for(let a of aDom){
        a.children[0].style.width = this.aWidth
      }
    })

    // 初始化数据
    this.getCityData().then(res => {
      if(!checkNull(this.editAreaParamsTemp)){
        if(typeof(this.editAreaParamsTemp) == ‘string‘){
          this.editAreaParamsIsStrHandel()
        }

        this.areaParams = this.editAreaParamsTemp;
        this.showDataHandel(this.areaParams.provinceCode);
      }
    });
  },


  methods:{
    // 加载地点数据,三级
    getCityData:function(){
      return new Promise((resolve, reject)=>{
        var that = this;
        // 省市区数据分类
        for (var item in this.mapJson) {
          if (item.match(/0000$/)) {//省
            that.defaultProvince.push({id: item, value: this.mapJson[item], children: []})
          } else if (item.match(/00$/)) {//市
            that.defaultCity.push({id: item, value: this.mapJson[item], children: []})
          } else {//区
            that.defaultArea.push({id: item, value: this.mapJson[item]})
          }
        }
        this.unlimitTemp && that.defaultProvince.unshift({id:‘不限‘, vlaue:‘不限‘, children:[]})
        
        resolve(‘success_p‘)

        // 分类市级
        for (var index in that.defaultProvince) {

          for (var index1 in that.defaultCity) {
            if (that.defaultProvince[index].id.slice(0, 2) === that.defaultCity[index1].id.slice(0, 2)) {
              that.defaultProvince[index].children.push(that.defaultCity[index1])
            }
          }

          this.unlimitTemp && that.defaultProvince[index].children.unshift({id:‘不限‘, vlaue:‘不限‘, children:[{id:‘不限‘, value:‘不限‘}]})
        }
        resolve(‘success_c‘)

        // 分类区级
        for(var item1 in that.defaultCity) {

          for(var item2 in that.defaultArea) {
            if (that.defaultArea[item2].id.slice(0, 4) === that.defaultCity[item1].id.slice(0, 4)) {
              that.defaultCity[item1].children.push(that.defaultArea[item2])
            }
          }

          this.unlimitTemp && that.defaultCity[item1].children.unshift({id:‘不限‘, vlaue:‘不限‘})
        }
        resolve(‘success_a‘)
      })
    },

    // 选省
    choseProvince:function(e) {
      for (var index2 in this.defaultProvince) {
        if (e === this.defaultProvince[index2].id || e === this.defaultProvince[index2].value) {
          this.cityArray = this.defaultProvince[index2].children
          this.areaArray = this.defaultProvince[index2].children[0].children;

          // 省
          this.queryParam.province = this.defaultProvince[index2].id
          this.queryParamText.province = this.defaultProvince[index2].value

          // 市
          this.areaParams.cityCode = this.defaultProvince[index2].children[0].id;
          this.queryParam.city = this.cityArray[0].id
          this.queryParamText.city = this.cityArray[0].value

          // 区
          this.areaParams.areaCode = this.defaultProvince[index2].children[0].children[0].id
          this.queryParam.area = this.areaArray[0].id
          this.queryParamText.area = this.areaArray[0].value

          this.$emit("queryParamText",this.queryParamText, this.fatherIndex)
          this.$emit("getAreaParam",this.queryParam, this.fatherIndex)
        }
      }
    },

    // 回显
    showDataHandel: function(e){
      console.log(‘回显:‘,e)
      for (var index2 in this.defaultProvince) {
        if (e === this.defaultProvince[index2].id || e === this.defaultProvince[index2].value) {
          e = this.defaultProvince[index2].id

          // 省
          this.areaParams.provinceCode = this.defaultProvince[index2].id
          this.queryParam.province = e
          this.queryParamText.province = this.defaultProvince[index2].value

          this.cityArray = this.defaultProvince[index2].children
          console.log(‘城市列表:‘,this.cityArray)


          // 得到选择的城市列表
          let currentCity =  this.cityArray.filter((cityItem, cityIndex) =>{
            return cityItem.id == this.areaParams.cityCode || cityItem.value == this.areaParams.cityCode
          })[0]
          console.log(‘当前选择城市:‘, currentCity)
          this.queryParam.city = currentCity == undefined? "不限" : currentCity.id
          this.queryParamText.city = currentCity == undefined? "不限" : currentCity.value
          this.areaParams.cityCode = currentCity == undefined? "不限" : currentCity.id


          // 得到选择的区县列表
          this.areaArray = currentCity.children
          let currentArea = this.areaArray.filter((areaItem, areaIndex) => {
            return areaItem.id == this.areaParams.areaCode || areaItem.value == this.areaParams.areaCode
          })[0]
          console.log(‘当前选择区域:‘,currentArea)
          this.queryParam.area = currentArea == undefined? "不限" : currentArea.id;
          this.queryParamText.area = currentArea == undefined? "不限" : currentArea.value
          this.areaParams.areaCode = currentArea == undefined? "不限" : currentArea.id

          this.$emit("queryParamText",this.queryParamText, this.fatherIndex)
          this.$emit("getAreaParam",this.queryParam, this.fatherIndex)
        }
      }
    },

    // 字符串转换 例:北京市-北京市-东城区
    editAreaParamsIsStrHandel(){
      let array = this.editAreaParamsTemp.split(‘-‘)
      this.editAreaParamsTemp = {
        provinceCode: array[0],
        cityCode: array[1],
        areaCode: array[2]
      }
    },

    // 选市
    choseCity:function(e) {
      for (var index3 in this.defaultCity) {
        if (e === this.defaultCity[index3].id) {
          this.areaArray = this.defaultCity[index3].children
          this.areaParams.areaCode = this.defaultCity[index3].children[0].id

          this.queryParam.city = e
          this.queryParam.area = this.areaArray[0].id

          this.queryParamText.city = this.defaultCity[index3].value
          this.queryParamText.area = this.areaArray[0].value

          this.$emit("queryParamText",this.queryParamText, this.fatherIndex)
          this.$emit("getAreaParam",this.queryParam, this.fatherIndex)
        }
      }
    },

    // 选区
    choseBlock:function(e) {
      for(let item in this.areaArray){
        if(e === this.areaArray[item].id){
          this.queryParamText.area = this.areaArray[item].value
          this.queryParam.area = this.areaArray[item].id
          this.areaParams.areaCode = this.areaArray[item].id

          this.$emit("queryParamText",this.queryParamText, this.fatherIndex)
          this.$emit("getAreaParam",this.queryParam, this.fatherIndex)
        }
      }
    }
  },

}
</script>

三、父组件引入组件并使用

1、添加地址功能

  • Template:
<!-- 简单使用 -->
<area-linkAge @getAreaParam=‘getAreaParam‘ @queryParamText=‘queryParamText‘></area-linkAge>

<!-- 多个、含有不限,自定义宽高 -->
<areaLinkAgeVue pWidth="120px" cWidth="120px" aWidth="120px"  @queryParamText=‘queryParamText‘ :fatherIndex=‘index‘ unlimit=‘true‘/>
  • script
import areaLinkAge from "../../components/areaLinkAge";
components: {
  ‘area-linkAge‘: areaLinkAge,
},

data() {
   return {
       addressParam: {
         province: ‘‘,
         city: ‘‘,
         area: ‘‘,
         provinceText: ‘‘,
         cityText: ‘‘,
         areaText: ‘‘,
       }
   }
},

methods: {
  // 获取子组件选择区域后的数据 - 地址code
  getAreaParam(val){
      this.addressParam.province = val.province;
      this.addressParam.city = val.city;
      this.addressParam.area = val.area;
  },

  // 获取子组件选择区域后的数据 - 地址Text
  getAreaParam(val){
      this.addressParam.provinceText = val.provinceText;
      this.addressParam.cityText = val.cityText;
      this.addressParam.areaText = val.areaText;
  }
}

2、回显地址,支持多类型

(1)、支持类型举例:

  • "北京市-北京市-朝阳区"
  • "不限"、"不限-不限"
  • "不限-不限-不限"
  • {provinceCode:‘11000‘, cityCode:‘110100‘, areaCode:‘110105‘}
  • {provinceCode:‘北京市‘, cityCode:‘北京市‘, areaCode:‘朝阳区‘}

(2)、Template

<!-- 简单使用 -->
<area-linkAge @getAreaParam=‘getAreaParam‘ @queryParamText=‘queryParamText‘ :editAreaParams=‘editAreaParams‘ v-if="addrVisible"></area-linkAge>

<!-- 多个、含有不限,自定义宽高 -->
<div v-for="(addr,index) of workAddress">
  <areaLinkAgeVue pWidth="120px" cWidth="120px" aWidth="120px" :editAreaParams=‘addr‘ @queryParamText=‘queryParamText‘ :fatherIndex=‘index‘ unlimit=‘true‘/>
</div>

Tip:因为地址回显的信息是异步请求回来的,所以需要添加v-if,当数据回来是将v-if设置为true;

(3)、script

import areaLinkAge from "../../components/areaLinkAge";
components: {
  ‘area-linkAge‘: areaLinkAge,
},

data() {
   return {
       // !!! 回显的属性后面有Code
       editAreaParams: {
         provinceCode: ‘‘,
         cityCode: ‘‘,
         areaCode: ‘‘,
       },
       addrVisible:false
   }
},

methods: {
  // 获取子组件选择区域后的数据 - 地址code
  getAreaParam(val){
      this.editAreaParams.province = val.province;
      this.editAreaParams.city = val.city;
      this.editAreaParams.area = val.area;
  },

  // 获取子组件选择区域后的数据 - 地址Text
  getAreaParam(val){
      this.editAreaParams.provinceText = val.provinceText;
      this.editAreaParams.cityText = val.cityText;
      this.editAreaParams.areaText = val.areaText;
  },

  //xhr - 回显详情
  xhrDisplayInfo(){
     let param = {
       id: this.orderId
     }

     getDetailInsMerchant(param).then(res=>{
       if(res.statusCode === HTTP_CODE.suc){
         this.editAreaParams = res.data.address;  // "北京市-北京市-朝阳区"
         // this.editAreaParams.provinceCode = this.addInsMerchantParams.province;
         // this.editAreaParams.cityCode = this.addInsMerchantParams.city;
         // this.editAreaParams.areaCode = this.addInsMerchantParams.area;
       }
     })
   },

}

好了~  如果走到这一步就成功了。恭喜?? 

再见~ 江湖再见!

 来源:站长

以上是关于Vue 含有"不限"的省市区三级联动的组件的主要内容,如果未能解决你的问题,请参考以下文章

vue + mint-ui 省市区级联选择

vue实现Element-ui省市区三级联动(包含省市区文件)

省市区三级联动

Exacl怎么快递将地址变成省市区?

excel 地址提取省市县

vue中使用市区(地区)联动 复制三步完成