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

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

  然而當咱們轉向vue+element作項目時,會產生一個比較尷尬的問題。在element組件庫當中,對須要校驗的字段是經過在el-form-item這一組件標籤名上添加prop屬性來校驗的,若是依然按照之前的方法對省市聯動和地址欄分別校驗的話,就得把省市選擇和地址輸入分紅兩個el-form-item組件內蓉來寫,咱們能夠看一下,實際造成的佈局。html

  

  這就比較難受了,用戶原本也就是須要輸入個地址,咱們提供給用戶級聯選擇器的目的是方便用戶進行省市區的選擇,然而如今的狀況確是,用戶必須進行二次驗證。前端

  轉換思路,用戶也能夠把兩欄併成一欄,展現會比較好看一點。vue

    

  這麼來看佈局彷佛沒問題了,可是另外一個問題又產生了,element本省提供的校驗方案是經過el-form-item的屬性prop對用戶傳入的參數進行校驗。java

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

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

  在el-form-item上寫上prop='address',而後自定義校驗方法,經過validator進行校驗。api

  想法已經完成了,那麼若是項目當中不單單一處用到地址輸入的話,咱們是否是就有必要對該組件進行封裝,讓他成爲咱們的常備組件之一了。數組

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

  咱們的組件封裝的僅僅是級聯選擇器和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表單控件的功能,因此封裝起來也就更容易一點,也更容易理解。

相關文章
相關標籤/搜索