最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Vue+ElementUI的省市區(qū)地址選擇通用組件

 更新時間:2019年11月20日 09:41:58   作者:隨風(fēng)丶逆風(fēng)  
這篇文章主要介紹了基于Vue+ElementUI的省市區(qū)地址選擇通用組件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、緣由

在項(xiàng)目開發(fā)過程中,有一個需求是省市區(qū)地址選擇的功能,一開始想的是直接使用靜態(tài)地址資源庫本地打包,但這種方式不方便維護(hù),于是放棄。后來又想直接讓后臺返回全部地址數(shù)據(jù),然后使用級聯(lián)選擇器進(jìn)行選擇,但發(fā)現(xiàn)數(shù)據(jù)傳輸量有點(diǎn)大且處理過程耗時,于是又摒棄了這種方法。最后還是決定采用異步的方式進(jìn)行省市區(qū)地址選擇,即先查詢省份列表,然后根據(jù)選擇的省份code查詢城市列表,最后根據(jù)選擇的城市列表獲取區(qū)/縣列表,最終根據(jù)應(yīng)用場景不同,給出了兩種實(shí)現(xiàn)方案。

其中后臺總共需要提供4個接口,一個查詢所有省份的接口,一個根據(jù)省份code查詢其下所有城市的接口,一個根據(jù)城市code查詢其下所有區(qū)/縣的接口,以及一個根據(jù)地址code轉(zhuǎn)換成省市區(qū)三個code值的接口。

// 本人項(xiàng)目中使用的四個接口
`${this.API.province}/${countryCode}` // 根據(jù)國家code查詢省份列表,中國固定為156,可以拓展
`${this.API.city }/${provinceCode}` // 根據(jù)省份code查詢城市列表
`${this.API.area}/${cityCode}` // 根據(jù)城市code查詢區(qū)/縣列表
`${this.API.addressCode}/${addressCode}` // 地址code轉(zhuǎn)換為省市區(qū)code

二、基于el-cascader 級聯(lián)選擇器的單選擇框?qū)崿F(xiàn)方案

<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: { // 級聯(lián)選擇器的屬性配置
    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 && 先執(zhí)行的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>

最終效果如下(動圖):

截圖:

三、基于el-select選擇器的多選擇框?qū)崿F(xiàn)方案

lt;template>
 <div id="addressHorizontalSelect">
  <el-row>
   <el-col
    :span="span">
    <el-select
     size="small"
     v-model="provinceCode"
     @focus="getProvinces"
     @change="changeProvince"
     :placeholder="$t('省')"
     filterable>
     <el-option
      v-for="item in provinceList"
      :key="item.provinceCode"
      :label="item.provinceName"
      :value="item.provinceCode">
     </el-option>
    </el-select>
   </el-col>
   <el-col
    :span="span"
    v-if="!hideCity">
    <el-select
     size="small"
     v-model="cityCode"
     @focus="getCities"
     @change="changeCity"
     :placeholder="$t('市')"
     filterable>
     <el-option
      v-for="item in cityList"
      :key="item.cityCode"
      :label="item.cityName"
      :value="item.cityCode">
     </el-option>
    </el-select>
   </el-col>
   <el-col
    :span="span"
    v-if="!hideCity && !hideArea">
    <el-select
     size="small"
     v-model="areaCode"
     @focus="getAreas"
     @change="changeArea"
     :placeholder="$t('區(qū)/縣')"
     filterable>
     <el-option
      v-for="item in areaList"
      :key="item.areaCode"
      :label="item.areaName"
      :value="item.areaCode">
     </el-option>
    </el-select>
   </el-col>
  </el-row>
 </div>
</template>

<script>
export default {
 name: 'addressHorizontalSelect',

 components: {},

 props: {
  hideCity: { // 隱藏市
   type: Boolean,
   default: false
  },
  hideArea: { // 隱藏區(qū)/縣
   type: Boolean,
   default: false
  },
  addressCode: null // 地址編碼
 },

 model: {
  prop: 'addressCode',
  event: 'addressSelect'
 },

 data() {
  return {
   provinceList: [], // 省份列表
   cityList: [], // 城市列表
   areaList: [], // 區(qū)/縣列表
   provinceCode: '', // 省份編碼
   cityCode: '', // 城市編碼
   areaCode: '', // 區(qū)/縣編碼
   cityFlag: false, // 避免重復(fù)請求的標(biāo)志
   provinceFlag: false,
   areaFlag: false
  }
 },

 computed: {
  span () {
   if (this.hideCity) {
    return 24
   }
   if (this.hideArea) {
    return 12
   }
   return 8
  }
 },

 watch: {
 },

 created () {
  this.getProvinces()
 },

 methods: {
  /**
   * 獲取數(shù)據(jù)
   * @param {Array} array 列表
   * @param {String} url 請求url
   * @param {String} code 編碼(上一級編碼)
   */
  fetchData (array, url, code) {
   this.$http({
    method: 'get',
    url: url + '/' + code
   })
   .then(res => {
    if (res.data.code === this.API.SUCCESS) {
     let body = res.data.body || []
     array.splice(0, array.length, ...body)
    }
   })
   .catch(err => {
    console.log(err)
   })
   .finally(res => {
   })
  },
  // 根據(jù)國家編碼獲取省份列表
  getProvinces () {
   if (this.provinceFlag) {
    return
   }
   this.fetchData(this.provinceList, this.API.province, 156)
   this.provinceFlag = true
  },
  // 省份修改,拉取對應(yīng)城市列表
  changeProvince (val) {
   this.fetchData(this.cityList, this.API.city, this.provinceCode)
   this.cityFlag = true
   this.cityCode = ''
   this.areaCode = ''
   this.$emit('addressSelect', val)
  },
  // 根據(jù)省份編碼獲取城市列表
  getCities () {
   if (this.cityFlag) {
    return
   }
   if (this.provinceCode) {
    this.fetchData(this.cityList, this.API.city, this.provinceCode)
    this.cityFlag = true
   }
  },
  // 城市修改,拉取對應(yīng)區(qū)域列表
  changeCity (val) {
   this.fetchData(this.areaList, this.API.area, this.cityCode)
   this.areaFlag = true
   this.areaCode = ''
   this.$emit('addressSelect', val)
  },
  // 根據(jù)城市編碼獲取區(qū)域列表
  getAreas () {
   if (this.areaFlag) {
    return
   }
   if (this.cityCode) {
    this.fetchData(this.areaList, this.API.area, this.cityCode)
   }
  },
  // 區(qū)域修改
  changeArea (val) {
   this.$emit('addressSelect', val)
  },
  // 重置省市區(qū)/縣編碼
  reset () {
   this.provinceCode = '',
   this.cityCode = '',
   this.areaCode = ''
  },
  // 地址編碼轉(zhuǎn)換成省市區(qū)列表
  addressCodeToList (addressCode) {
   if (!addressCode) return false
   this.$http({
    method: 'get',
    url: this.API.addressCode + '/' + addressCode
   })
   .then(res => {
    let data = res.data.body
    if (!data) return
    if (data.provinceCode) {
     this.provinceCode = data.provinceCode
     this.fetchData(this.cityList, this.API.city, this.provinceCode)
    } else if (data.cityCode) {
     this.cityCode = data.cityCode
     this.fetchData(this.areaList, this.API.area, this.cityCode)
    } else if (data.areaCode) {
     this.areaCode = data.areaCode
    }
   })
   .finally(res => {
   })
  }
 },

 watch: {
  addressCode: {
   deep: true,
   immediate: true,
   handler (newVal) {
    if (newVal) {
     this.addressCodeToList(newVal)
    } else {
     this.$nextTick(() => {
      this.reset()
     })
    }
   }
  }
 }
}
</script>

<style lang="less" scoped>
</style>

實(shí)現(xiàn)效果如下(動圖):

四、總結(jié)

兩個組件都實(shí)現(xiàn)了雙向綁定,根據(jù)場景不同可以使用不同的組件,如果讀者有需求,根據(jù)自己的接口和場景進(jìn)行修改即可。

當(dāng)拓展至大洲-國家-省-市-區(qū)-街道等時,第一種級聯(lián)選擇器的方案就會暴露出拓展性較差的問題,隨著層級加深,數(shù)據(jù)結(jié)構(gòu)會變得復(fù)雜,而第二種方案明顯可拓展性更強(qiáng)

相關(guān)文章

  • VSCode插件安裝完成后的配置(常用配置)

    VSCode插件安裝完成后的配置(常用配置)

    這篇文章主要介紹了VSCode插件安裝完成后的配置,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • element-ui中如何給el-table的某一行或某一列加樣式

    element-ui中如何給el-table的某一行或某一列加樣式

    本文主要介紹了element-ui中怎么給el-table的某一行或某一列加樣式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Vue中Layout內(nèi)部布局el-row、el-col的實(shí)現(xiàn)

    Vue中Layout內(nèi)部布局el-row、el-col的實(shí)現(xiàn)

    layout是一種非常方便的布局方式,本文主要介紹了Vue中Layout內(nèi)部布局el-row、el-col的實(shí)現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • Vue?echarts實(shí)例項(xiàng)目商家銷量統(tǒng)計(jì)圖實(shí)現(xiàn)詳解

    Vue?echarts實(shí)例項(xiàng)目商家銷量統(tǒng)計(jì)圖實(shí)現(xiàn)詳解

    Echarts,它是一個與框架無關(guān)的?JS?圖表庫,但是它基于Js,這樣很多框架都能使用它,例如Vue,估計(jì)IONIC也能用,因?yàn)槲业牧?xí)慣,每次新嘗試做一個功能的時候,總要新創(chuàng)建個小項(xiàng)目,做做Demo
    2022-09-09
  • vue修改對象的屬性值后頁面不重新渲染的實(shí)例

    vue修改對象的屬性值后頁面不重新渲染的實(shí)例

    今天小編就為大家分享一篇vue修改對象的屬性值后頁面不重新渲染的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • vue 如何將二維數(shù)組轉(zhuǎn)化為一維數(shù)組

    vue 如何將二維數(shù)組轉(zhuǎn)化為一維數(shù)組

    這篇文章主要介紹了vue 如何將二維數(shù)組轉(zhuǎn)化為一維數(shù)組,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 手把手教你如何運(yùn)行一個前端uniapp項(xiàng)目

    手把手教你如何運(yùn)行一個前端uniapp項(xiàng)目

    這篇文章主要介紹了如何設(shè)置和運(yùn)行一個基于uni-app框架的項(xiàng)目,包括安裝必要的軟件、克隆項(xiàng)目并安裝依賴,以及如何使用HBuilderX進(jìn)行項(xiàng)目運(yùn)行和調(diào)試,需要的朋友可以參考下
    2025-01-01
  • ElementUI動態(tài)渲染el-table的實(shí)現(xiàn)過程

    ElementUI動態(tài)渲染el-table的實(shí)現(xiàn)過程

    在前端開發(fā)中,表格是不可或缺的一部分,無論是數(shù)據(jù)展示、數(shù)據(jù)錄入,還是數(shù)據(jù)分析,表格都扮演著重要的角色,而在Vue.js生態(tài)系統(tǒng)中,ElementUI提供了一個強(qiáng)大且靈活的表格組件——el-table,本文將帶你深入了解如何使用ElementUI動態(tài)渲染el-table,并詳細(xì)探討其原理及實(shí)現(xiàn)過程
    2024-08-08
  • Vue 表單控件綁定的實(shí)現(xiàn)示例

    Vue 表單控件綁定的實(shí)現(xiàn)示例

    本篇文章主要介紹了Vue 表單控件綁定的實(shí)現(xiàn)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • vue動態(tài)綁定background的方法

    vue動態(tài)綁定background的方法

    background是background-color,background-image,background-repeat,background-attachment,background-position,background-size等屬性的縮寫,本文我用動態(tài)綁定background-image來舉例,感興趣的朋友跟隨小編一起看看吧
    2023-10-10

最新評論

石屏县| 惠来县| 山阳县| 格尔木市| 汝南县| 尤溪县| 九江县| 霸州市| 滦南县| 诏安县| 柘荣县| 进贤县| 南平市| 沙坪坝区| 扶余县| 永年县| 永登县| 犍为县| 加查县| 新乡市| 泌阳县| 建湖县| 桃江县| 灵石县| 天峻县| 临清市| 沙湾县| 乐陵市| 迭部县| 峡江县| 托克逊县| 宁陵县| 嘉峪关市| 泰来县| 宁乡县| 大荔县| 桦甸市| 雅江县| 维西| 南溪县| 铜鼓县|