利用element-ui封裝地址輸入的組件


  我們前端做項目時,難免會遇到地址輸入,多數情況下,我們都是提供一個省市三級聯動,加上具體地址輸入的Input輸入框給用戶,用以獲取用戶需要輸入的真實地址。在需要對用戶輸入的數據進行校驗的時候,我們會單獨針對省市的三級聯動和具體地址欄單獨校驗。也基本上能夠完成項目需求。

  然而當我們轉向vue+element做項目時,會產生一個比較尷尬的問題。在element組件庫當中,對需要校驗的字段是通過在el-form-item這一組件標簽名上添加prop屬性來校驗的,如果依然按照以前的方法對省市聯動和地址欄分別校驗的話,就得把省市選擇和地址輸入分成兩個el-form-item組件內蓉來寫,我們可以看一下,實際形成的布局。

  

  這就比較難受了,用戶本來也就是需要輸入個地址,我們提供給用戶級聯選擇器的目的是方便用戶進行省市區的選擇,然而現在的情況確是,用戶必須進行二次驗證。

  轉換思路,用戶也可以把兩欄並成一欄,展示會比較好看一點。

    

  這么來看布局似乎沒問題了,但是另一個問題又產生了,element本省提供的校驗方案是通過el-form-item的屬性prop對用戶傳入的參數進行校驗。

  也就是說prop必須是字符串,那么這時候,就沒辦法對兩個字段同時校驗了,唯一的方案似乎就變成了:把這兩個字段變成一個對象,通過自定義校驗方法來校驗該對象內的數據的值。類似於:

address:{
    district:[],
    address:''
}

  在el-form-item上寫上prop='address',然后自定義校驗方法,通過validator進行校驗。

  想法已經完成了,那么如果項目當中不僅僅一處用到地址輸入的話,我們是不是就有必要對該組件進行封裝,讓他成為我們的常備組件之一了。

  好吧!那就開始封裝組件了。

  我們的組件封裝的僅僅是級聯選擇器和Input輸入框,並不包含校驗規則,畢竟是還有其他需要校驗的組件。

  組件的內容可能就很簡單了。

  一個.vue文件, template:

<el-row
    :gutter="16"
    type="flex"
    justify="space-between"
  >
    <el-col :span="12">
      <el-cascader
        v-model="dis"
        :options="regionData"
        @change="handleAddressChange"
        style="width: 100%"
        filterable
      />
    </el-col>
    <el-col :span="12">
      <el-input
        v-model="address"
        placeholder="請輸入地址"
        @change="handleChange"
      />
    </el-col>
  </el-row>

  script:

  

import { regionData, CodeToText, TextToCode } from 'element-china-area-data'
export default {
  name: 'VAddress',
  props: {
    value: {
      type: Object,
      default () {
        return {
          address: '',
          areaCity: '',
          areaCode: '',
          areaDistrict: '',
          areaProvince: ''
        }
      }
    }
  },
  model: {
    prop: 'value',
    event: 'change'
  },
  data () {
    return {
      dis: [],
      regionData,
      mapLabel: TextToCode,
      mapCode: CodeToText,
      ...this.value
    }
  },
  methods: {
    handleChange (e) {
      let val = {
        ...this.value,
        address: this.address
      }
      this.$emit('update:value', val)
      this.$emit('change', val)
    },
    handleAddressChange (values) {
      console.log(values)
      const b = ['areaProvince', 'areaCity', 'areaDistrict']
      if (values.length > 0) {
        let initialValue = {
          ...this.value,
          'areaProvince': '',
          'areaCity': '',
          'areaDistrict': '',
          'areaCode': values[values.length - 1]
        }
        const val = values.reduce((acc, curret, index) => {
          let value = this.mapCode[curret]
        
          return {
            ...acc,
            [b[index]]: value
          }
        }, initialValue)
        this.$emit('change', val)
        // sync更新
        // this.$emit('update:value', val)
      }
    },
    getCurrentRegion (val) {
      let address = val
      if (!Array.isArray(val) && typeof val === 'object') {
        let { areaProvince, areaCity = '', areaCode } = val
        address = [this.mapLabel[areaProvince], this.mapLabel[areaCity], areaCode]
        if (address.some(item => item === undefined)) address = []
      }
      return address
    },
    initDis (val) {
      this.dis = this.dis.length === 0 ? this.getCurrentRegion(val) : this.dis
    }
  },
  created () {
    if (this.regionData.length > 0 && this.value.areaCode) {
      this.initDis(this.value)
    }
  },
  watch: {
    value: {
      handler (val) {
        this.address = val.address
        if (this.regionData.length > 0) {
          this.initDis(val)
        }
        if (Object.values(val).every(item => !item)) this.dis = []
      },
      deep: true
    }
  }
}

  需要注意的一個是:

model: {
    prop: 'value',
    event: 'change'
}

  具體解釋請轉到vue.js官方文檔,我只簡單說一句,就是提供給組件使用時綁定v-model,因為v-model默認傳遞的是value屬性,處理的是input事件,而通過在子組件定義model屬性,我們就可以修改v-model處理的事件和傳遞的屬性。因為很正常,我們這里有兩個form表單控件的內容,肯定沒辦法依賴v-model的input事件進行處理。如果實在不喜歡這種寫法,也可以在組件使用時,避開v-model的用法,轉而通過:value.sync進行屬性傳遞,在事件處理是通過this.$emit('update:value', val)來進行類似處理,這也就是看起來沒有v-model那么牛X一樣,其實結果是一致的。

  我們在組件內分別對級聯選擇器和Input輸入框做change事件處理,從而獲取到最新的數據,轉換成使用該組件的父組件內,關於級聯選擇器的change事件,依賴於各個公司后台開發人員需要前端傳回什么樣的數據,進行處理。

  我們的項目當中,后台需要省市區的數據格式為areaProvince, areaCity, areaDistrict, areaCode,所以在級聯選擇器change的時候,我需要及時的將其獲取到的數組(省市區的code值),轉換成對應的具體的省份、城市、區,加上區的areaCode,然后傳遞給后台,具體的得依賴項目需求各自處理。

  這是vue+element的地址輸入的組件封裝,后面還會有一個react+antd關於地址輸入的組件封裝,相較於element,antd提供了自定義form表單控件的功能,所以封裝起來也就更容易一點,也更容易理解。

  

 

  


免責聲明!

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



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