vue手動制作地址選擇器


方法一:4級地址選擇器(基於elementui   Cascader 級聯選擇器) 推薦

效果圖:

 組件源碼:

<template>
  <div class="select-city" ref="selectCity">
    <el-cascader
      :options="options2"
      @change="change"
      v-model="selCity"
      :props="props"
    ></el-cascader>
  </div>

</template>

<style>
  .select-city .el-input{
    width: 350px;
  }
</style>

<script>
  import addressData from 'common/json/class4new.json'
  export default {
    props: {
      value: {
        required: true
      },
      getCityName: {

      }
    },
    data() {
      return {
        options2: addressData,
        props: {
          label: 'name',
          value: 'id',
          children: 'children'
        },
        selCity: []
      }
    },
    watch: {
      value (val) {
        this.init()
      }
    },
    created() {
      // 組件剛載入並不會觸發watch value
    },
    methods: {
      init() {
        let el = this.$refs.selectCity
        if (!this.value) {
          if (this.selCity.length) {
            this.selCity = []
            el.getElementsByClassName('el-cascader__label')[0].innerHTML = ''
            el.getElementsByClassName('el-input__inner')[0].setAttribute('placeholder', '請選擇')
          }
        } else {
          if (this.selCity.length===0 || this.selCity[3] !== this.value) {
            this.selCity[0] = this.value.substr(0, 2) + '0000'
            this.selCity[1] = this.value.substr(0, 4) + '00000000'
            this.selCity[2] = this.value.substr(0, 6) + '000000'
            this.selCity[3] = this.value
            let name = this.getNode().join('<span>/</span>')
            el.getElementsByClassName('el-cascader__label')[0].innerHTML = name
            el.getElementsByClassName('el-input__inner')[0].setAttribute('placeholder', '')
          }
        }
      },
      change(val) {
        // 只有選完了,才會將數據返回給父組件
        this.$emit('input', val[3])
        this.returnCityName()
      },
      returnCityName() {
        if (typeof this.getCityName === 'function') {
          this.getCityName(this.getNode().join(''))
        }
      },
      getNode() {
        let name = []
        this.options2.filter(v => {
          if (name[0]) return
          if (v.id===this.selCity[0]) {
            name.push(v.name)
            v.children.filter(v => {
              if (name[1]>0) return
              if (v.id===this.selCity[1]) {
                name.push(v.name)
                v.children.filter(v => {
                  if (name[2]>0) return
                  if (v.id===this.selCity[2]) {
                    name.push(v.name)
                    v.children.filter(v => {
                      if (name[3]>0) return
                      if (v.id===this.selCity[3]) {
                        name.push(v.name)
                        return false
                      }
                    })
                  }
                })
              }
            })
          }
        })
        return name
      }
    }
  }
</script>

 

方法二:4級地址選擇器(基於elementui  select選擇器 )

適用環境: PC

開發過程中遇到的問題:

1. 自定義組件如何做到雙向數據綁定

2. 自定義組件在剛加載完畢,會執行一次created和mounted,當組件上綁定的v-model變化時候,也就是做編輯的時候,觸發的watch監聽的value方法

3.這個程序剛好是一個自循環,一旦更新了地址組件綁定的值立刻就觸發this.$emit,把執行結果返回至父組件。這邊需要visible-change(下拉框出現/隱藏時觸發, 出現則為 true,隱藏則為 false),來組件地址組件數據的初始化,導致向父組件傳遞錯誤數據

小小的程序,把我折騰了好幾天,仔細想想,兩個2原因:1.缺少自己寫組件的經歷導致對vue的很多api不熟悉  2.缺乏獨自面對困難的恆心

效果圖:

 

地址組件代碼:

<style>
  .block .el-select{display: block;}
  .block .el-select{margin-bottom: 20px}
</style>

<template>
  <div>
    <div :class="{block: block}">
      <el-select v-model="proviceCode" popper-class="tab-select" placeholder="請選擇省" @change="proviceChange" @visible-change="vChange($event, 'provice')">
        <el-option
          v-for="(item, index) in provice"
          :key="item.id"
          :label="item.name"
          :value="item.id">
        </el-option>
      </el-select>
      <el-select v-model="cityCode" popper-class="tab-select" placeholder="請選擇市" @change="cityChange" @visible-change="vChange($event, 'city')">
        <el-option
          v-for="(item, index) in city"
          :key="item.id"
          :label="item.name"
          :value="item.id">
        </el-option>
      </el-select>
      <el-select v-model="areaCode" popper-class="tab-select" placeholder="請選擇區或縣" @change="areaChange" @visible-change="vChange($event, 'area')">
        <el-option
          v-for="(item, index) in area"
          :key="item.id"
          :label="item.name"
          :value="item.id">
        </el-option>
      </el-select>
      <el-select v-model="villageCode"  popper-class="tab-select" placeholder="請選擇鄉" @change="villageChange"  @visible-change="vChange($event, 'village')">
        <el-option
          v-for="(item, index) in village"
          :key="item.id"
          :label="item.name"
          :value="item.id">
        </el-option>
      </el-select>
      <input type="hidden" :value="value">
    </div>
  </div>
</template>

<script>
  import address from 'common/json/class4new.json'
  export default {
    props: {
      block: {
        type: Boolean,
        default: false
      },
      value: {
        required: false
      }
    },
    data() {
      return {
        provice: address,
        city: [],
        area: [],
        village: [],
        proviceCode: '',
        cityCode: '',
        areaCode: '',
        villageCode: '',
        isOpen: {
          provice: false,
          city: false,
          area: false,
          village: false
        }
      }
    },
    watch: {
      value (val) {
        if (val.code !== this.villageCode) {
          this.init()
        }
      }
    },
    created() {
      this.villageCode = this.value.code
      this.init()
    },
    mounted () {
      this.$root.eventHub.$on("reset-addressSelect", () => {
        this.city = []
        this.area = []
        this.village = []
        this.proviceCode = ''
        this.cityCode = ''
        this.areaCode = ''
        this.villageCode = ''
      })
    },
    methods: {
      vChange(val, type) {
        this.isOpen[type] = val
      },
      init() {
        let code = this.value.code;
        if (code) {
          let v = code.toString()
          this.proviceCode = v.substr(0,2) + '0000'
          this.cityCode = v.substr(0,4)+'00000000'
          this.areaCode = v.substr(0,6)+'000000'
          this.villageCode = v
          this.proviceChange(this.proviceCode).then(_ => {
            this.cityChange(this.cityCode).then(_ => {
              this.areaChange(this.areaCode)
            })
          })
        } else {
          this.city = []
          this.area = []
          this.village = []
          this.proviceCode = ''
          this.cityCode = ''
          this.areaCode = ''
          this.villageCode = ''
        }
      },
      proviceChange(id) {
        return new Promise((resolve, reject) => {
          if (this.isOpen.provice) {
            this.city = []
            this.area = []
            this.village = []
            this.cityCode = ''
            this.areaCode = ''
            this.villageCode = ''
          }
          this.provice.filter(v => {
            if (v.id === id) {
              this.city = v.children
              resolve()
              return false
            }
          })
        })
      },
      cityChange(id) {
        return new Promise((resolve, reject) => {
          if (this.isOpen.city) {
            this.area = []
            this.village = []
            this.areaCode = ''
            this.villageCode = ''
          }
          this.city.filter(v => {
            if (v.id === id) {
              this.area = v.children
              resolve()
              return false
            }
          })
        })
      },
      areaChange(id) {
        return new Promise((resolve, reject) => {
          if (this.isOpen.area) {
            this.village = []
            this.villageCode = ''
          }
          this.area.filter(v => {
            if (v.id === id) {
              this.village = v.children
              resolve()
              return false
            }
          })
        })
      },
      villageChange(id) {
        var text = []
        this.provice.filter(v => {
          if (v.id === this.proviceCode) {
            text.push(v.name)
            return false
          }
        })
        this.city.filter(v => {
          if (v.id === this.cityCode) {
            text.push(v.name)
            return false
          }
        })
        this.area.filter(v => {
          if (v.id === this.areaCode) {
            text.push(v.name)
            return false
          }
        })
        this.village.filter(v => {
          if (v.id === id) {
            text.push(v.name)
            return false
          }
        })
        this.$emit('input', {
          text: text.join(''),
          code: id
        })
      }
    }
  }
</script>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM