当前位置 主页 > 服务器问题 > Linux/apache问题 >

    基于Vue+ElementUI的省市区地址选择通用组件

    栏目:Linux/apache问题 时间:2019-11-21 01:20

    一、缘由

    在项目开发过程中,有一个需求是省市区地址选择的功能,一开始想的是直接使用静态地址资源库本地打包,但这种方式不方便维护,于是放弃。后来又想直接让后台返回全部地址数据,然后使用级联选择器进行选择,但发现数据传输量有点大且处理过程耗时,于是又摒弃了这种方法。最后还是决定采用异步的方式进行省市区地址选择,即先查询省份列表,然后根据选择的省份code查询城市列表,最后根据选择的城市列表获取区/县列表,最终根据应用场景不同,给出了两种实现方案。

    其中后台总共需要提供4个接口,一个查询所有省份的接口,一个根据省份code查询其下所有城市的接口,一个根据城市code查询其下所有区/县的接口,以及一个根据地址code转换成省市区三个code值的接口。

    // 本人项目中使用的四个接口
    `${this.API.province}/${countryCode}` // 根据国家code查询省份列表,中国固定为156,可以拓展
    `${this.API.city }/${provinceCode}` // 根据省份code查询城市列表
    `${this.API.area}/${cityCode}` // 根据城市code查询区/县列表
    `${this.API.addressCode}/${addressCode}` // 地址code转换为省市区code

    二、基于el-cascader 级联选择器的单选择框实现方案

    <template>
     <el-row>
      <el-cascader
       size="small"
       :options="city.options"
       :props="props"
       v-model="cityValue"
       @active-item-change="handleItemChange"
       @change="cityChange">
      </el-cascader>
     </el-row>
    </template>
    
    <script>
    export default {
     name: 'addressSelector',
     props: {
      areaCode: null
     },
    
     model: {
      prop: 'areaCode',
      event: 'cityChange'
     },
    
     data () {
      return {
       // 所在省市
       city: {
        obj: {},
        options: []
       },
       props: { // 级联选择器的属性配置
        value: 'value',
        children: 'cities',
        checkStrictly: true
       },
       cityValue: [], // 城市代码
      }
     },
     computed: {
     },
     created () {
      this._initData()
     },
     mounted () {
     },
     methods: {
      _initData () {
       this.$http({
        method: 'get',
        url: this.API.province + '/156' // 中国
       }).then(res => {
        this.city.options = res.data.body.map(item => { // 所在省市
         return {
          value: item.provinceCode,
          label: item.provinceName,
          cities: []
         }
        })
       })
      },
      getCodeByAreaCode (code) {
       if (code == undefined) return false
       this.$http({
        method: 'get',
        url: this.API.addressCode + '/' + code
       })
       .then(res => {
        if (res.data.code === this.API.SUCCESS) {
         let provinceCode = res.data.body.provinceCode
         let cityCode = res.data.body.cityCode
         let areaCode = res.data.body.areaCode
         this.cityValue = [provinceCode, cityCode, areaCode]
         this.handleItemChange([provinceCode, cityCode])
        }
       })
       .finally(res => {
       })
      },
      handleItemChange (value) {
       let a = (item) => {
        this.$http({
         method: 'get',
         url: this.API.city + '/' + value[0],
        }).then(res => {
         item.cities = res.data.body.map(ite => {
          return {
           value: ite.cityCode,
           label: ite.cityName,
           cities: []
          }
         })
         if(value.length === 2){ // 如果传入的value.length===2 && 先执行的a(),说明是传入了areaCode,需要初始化多选框
          b(item)
         }
        }).finally(_ => {
        })
       }
       let b = (item) => {
        if (value.length === 2) {
         item.cities.find(ite => {
          if (ite.value === value[1]) {
           if (!ite.cities.length) {
            this.$http({
             method: 'get',
             url: this.API.area + '/' + value[1]
            }).then(res => {
             ite.cities = res.data.body.map(ite => {
              return {
               value: ite.areaCode,
               label: ite.areaName,
              }
             })
            }).finally(_ => {
            })
           }
          }
         })
        }
       }
       this.city.options.find(item => {
        if (item.value === value[0]) {
         if (item.cities.length) {
          b(item)
         } else {
          a(item)
         }
         return true
        }
       })
      },
      getCityCode () {
       return this.cityValue[2]
      },
      reset () {
       this.cityValue = []
      },
      cityChange (value) {
       if (value.length === 3) {
        this.$emit('cityChange', value[2])
       } else {
        this.$emit('cityChange', null)
       }
      }
     },
     watch: {
      areaCode: {
       deep: true,
       immediate: true,
       handler (newVal) {
        if (newVal) {
         this.getCodeByAreaCode(newVal)
        } else {
         this.$nextTick(() => {
          this.reset()
         })
        }
       }
      }
     }
    }
    </script>
    
    <style lang="less" scoped>
    </style>