行政區(qū)劃選擇器異步數(shù)據(jù) vue antd

前言

  • 在網(wǎng)上搜索行政區(qū)劃(省市區(qū))級聯(lián)選擇的時候沒有發(fā)現(xiàn)數(shù)據(jù)源是異步請求接口來的(有的例子是是異步但是沒有交代設(shè)置默認值如何操作 所以自己應公司需求改裝了一下)
  • 此組件依賴于ant design of vuehttps://www.antdv.com/components/cascader-cn/
  • 效果


    K8C`A3_9PEZPPS`MBMQBNNL.png

介紹

  • 接口格式
    {
      "id": "1194501203665408001",
      "createBy": "admin",
      "createTime": "2019-11-13 14:24:14",
      "updateBy": null,
      "updateTime": null,
      "sysOrgCode": "A01",
      "hasChild": "0",
      "code": "460101000000",
      "name": "市轄區(qū)",
      "pcode": "460100000000",
      "remarks": null,
      "zeroReport": "0"
    },
    {
      "id": "1194501203665408002",
      "createBy": "admin",
      "createTime": "2019-11-13 14:24:14",
      "updateBy": null,
      "updateTime": null,
      "sysOrgCode": "A01",
      "hasChild": "1",
      "code": "460105000000",
      "name": "秀英區(qū)",
      "pcode": "460100000000",
      "remarks": null,
      "zeroReport": "0"
    }

通過code 代表自身所在行政區(qū)代碼 pcode 是上一級代碼 haschild 代表是否有下一級(0無 1有)

  • 組件
    首先字段值和cascader要求的對應字段是不一致的 我們需要自定義字段名更多請了解原組件介紹
<template>
  <a-cascader
//數(shù)據(jù)源
    :options="options"
//選中項改變時觸發(fā)事件
    @change="onChange"
//在選中當前項的時候做的事情
    :loadData="loadData"
//當前無選中的時候顯示的值
    :placeholder="placeholder"
//對應接口字段構(gòu)建樹
    :fieldNames="{ label: 'name', value: 'code', children: 'children' }"
//設(shè)置默認值  類似于v-model
    :value="values"
//設(shè)置key 用于更新dom
    :key="type"
//選擇即改變的關(guān)鍵詞
    changeOnSelect
//是否禁用
    :disabled="disabled"
  />
</template>

相應的我們要在data上綁定相應的值

  data() {
    return {
      options: [],
      fieldNames: ['city', 'county', 'township', 'village'],
      values: [],
      type: true
    }
  }

接收項

  props: {
    placeholder: { type: String, default: '請選擇' },
    //接收默認值數(shù)組與filedNames中的字段對應的值
    defaultvalue: {
      type: Array,
      default: () => []
    },
    disabled: {
      type: Boolean,
      default: false
    }
  }

在method中

//此方法只運行一次
    loadfisrtData() {
    //首先先請求第一級的所需數(shù)據(jù)源
      axios.get('/dict/nhDictXzq/getList', { params: { pcode: 460000000000 } }).then(res => {
        let arr = res.result
        arr.forEach(element => {
        //每一項添加isleaf 
          element.isLeaf = false
        })
//賦值給數(shù)據(jù)源
        this.options = arr
      })
    },
//選中項改變時觸發(fā)事件 [460300000000,460300000000,460300000000] 類似這樣 選擇幾級對應長度就有多少
    onChange(arr) {
// 設(shè)置默認值
      this.values = [...arr]
// 我的業(yè)務(wù)需求 每次點擊后返回相應的{key:value} 如{city:460300000000,460300000000,460300000000} 這也是設(shè)置filedNames的原因
      let obj = {}
      if (arr.length == 0) {
        obj = null
        this.loadfisrtData()
        this.$emit('onChanged', obj)
        return
      }
      const length = arr.length
      // 取出所得數(shù)組 最后一位;
      const value = arr[length - 1]
      const key = this.fieldNames[length - 1]
      obj[key] = value
      // 返回最后一位對應結(jié)果
      this.$emit('onChanged', obj)
      // 返回對應關(guān)系結(jié)果
      let newObj = {}
      let nameArray = {}
      let keyarr = [...this.fieldNames]
//數(shù)據(jù)庫中特殊情況 因為個別市的級聯(lián)只有兩級 或者三級(一般為四級)做特別處理
      if (arr[0] == 460300000000 || arr[0] == 460100000000 || arr[0] == 460200000000) {
//取出對應漢字(這個組件沒有取出組件上顯示的值的方法 所以只能自己從數(shù)據(jù)源中取 用對應的級聯(lián)等級的code使用遞歸?。?        this.getCodeName(nameArray, this.options, 0, keyarr, arr)
        // {'cityname':'', 'countyname':'', 'townshipname':'', 'villagename':''}
        keyarr.forEach((ins, index) => {
          newObj[ins] = arr[index]
        })
        arr.length == 4 ? this.$emit('resultCodeArray', { nameArray, newObj }) : this.$emit('resultCodeArray', null)
      } else if (arr[0] == 460400499000) {
        keyarr.splice(1, 2)
        this.getCodeName(nameArray, this.options, 0, keyarr, arr)
        // this.getCodeName(nameArray, this.options, 0, keyarr)
        keyarr.forEach((ins, index) => {
          newObj[ins] = arr[index]
        })
        arr.length == 2 ? this.$emit('resultCodeArray', { nameArray, newObj }) : this.$emit('resultCodeArray', null)
      } else {
        // let keys = ['city', 'township', 'village']
        //{'cityname':'','townshipname':'', 'villagename':''}
        keyarr.splice(1, 1)
        this.getCodeName(nameArray, this.options, 0, keyarr, arr)
        keyarr.forEach((ins, index) => {
          newObj[ins] = arr[index]
        })
        arr.length == 3 ? this.$emit('resultCodeArray', { nameArray, newObj }) : this.$emit('resultCodeArray', null)
      }*/
    },
    loadData(selectedOptions) {
//官方方法 取出當前項
      const targetOption = selectedOptions[selectedOptions.length - 1]
//判斷是否還有下一級 
      if (targetOption.hasChild == 0) {
        return
      }
      targetOption.loading = true
      axios.get('/dict/nhDictXzq/getList', { params: { pcode: targetOption.code } }).then(res => {
        targetOption.loading = false
        let arr = res.result
        arr.forEach(element => {
          element.isLeaf = false
        })
        targetOption.children = arr
//重新更新數(shù)據(jù)源
        this.options = [...this.options]
      })
    }

到這里就已經(jīng)完成了選擇了

  • 根據(jù)設(shè)置默認值顯示組件
    在這邊有個坑 這個組件是多個頁面公用的 所以不會一直觸發(fā)生命周期的鉤子我們只能去監(jiān)視默認值的變化 因為有的情景是需要設(shè)置默認值(取)有的不用的
  watch: {
    defaultvalue: function(value) {
//過濾掉默認值中的空值 原因就是有的是三級 有的是兩級
      this.values = value.filter(ins => {
        return ins !== ''
      })
      this.values.length > 0 && this.setDefault()
    }
  },
  mounted() {
//掛載后執(zhí)行獲取數(shù)據(jù)源操作
    this.loadfisrtData()
//把props的值給到data上面的值 后面要對values改變props傳來的值不推薦直接改變所以使用變量存起來
    this.values = [...this.defaultvalue]
  },

設(shè)置默認值到組件上

    setDefault() {
      //   console.log('訪問的values', this.values)
//最初的方法  獲取到所有的對應級聯(lián)數(shù)據(jù)在對靜態(tài)數(shù)據(jù)操作 格式轉(zhuǎn)換
      //   let promiseArr = []
      //   this.values.forEach(ins => {
      //     promiseArr.push(
      //       new Promise((resolve, reject) => {
      //         axios.get('/dict/nhDictXzq/getList', { params: { pcode: ins } }).then(res => {
      //           resolve(res.result)
      //         })
      //       })
      //     )
      //   })
      //   Promise.all(promiseArr).then(result => {
      //     console.log('result',JSON.stringify(result))
      //     // 先把result的數(shù)據(jù)結(jié)果集組裝
      //     let res = []
      //     this.values.forEach((ins, index) => {
      //       if (index + 1 < this.values.length) {
      //         result.forEach((c, index) => {
      //           let a = c.filter(i => {
      //             return i.code == this.values[index + 1]
      //           })
      //           if (a && a.length > 0) {
      //             a.isLeaf = false
      //             a.loading = false
      //             res.push(a)
      //             // 合并數(shù)組
      //             res = Array.prototype.concat.apply([], res)
      //             res = Array.from(new Set(res))
      //           }
      //         })
      //       }
      //     })
      //     for (var i = res.length; i > 0; i--) {
      //       if (res[i]) {
      //         res[i - 1].children = [res[i]]
      //       }
      //     }
      //     res = res[0]
      //     res.isLeaf = false
      //     res.loading = false
      //     let d = this.options.find(ins => {
      //       return ins.code == this.values[0]
      //     })
      //     d && (d.children = [res])
      //     // 更新dom
      //     this.type = !this.type
      //   })
//第二種使用遞歸方法 直接為他添加children屬性
      const p = this.options.find(ins => {
        return ins.code == this.values[0]
      })
      p && this.setChildren(p, 1, this.values, () => {
          // 更新dom
          this.type = !this.type
        })
    },
//parmas  父級 當前層級 傳入的默認值 遍歷后回調(diào)
    setChildren(parent, index, values, cb) {
      axios.get('/dict/nhDictXzq/getList', { params: { pcode: parent.code } }).then(res => {
//結(jié)束條件 最后一級是沒有子集的
        if (res.result.length == 0) {
          cb()
          return
        }
        parent.children = res.result
        res.result.forEach(ins => {
          ins.isLeaf = false
          ins.loading = false
          if (ins.code === values[index]) {
            index++
            this.setChildren(ins, index, values, cb)
          }
        })
      })
    }

到這里 這個組件就全部都介紹完了 因為是臨時做的所以沒有做的很通用如果沒有理解的可以聯(lián)系我....

  • 完整的代碼
<template>
  <a-cascader
    :options="options"
    @change="onChange"
    :loadData="loadData"
    :placeholder="placeholder"
    :fieldNames="{ label: 'name', value: 'code', children: 'children' }"
    :value="values"
    :key="type"
    changeOnSelect
    :disabled="disabled"
  />
</template>
<script>
import { axios } from '@/utils/request'
export default {
  props: {
    placeholder: { type: String, default: '請選擇' },
    defaultvalue: {
      type: Array,
      default: () => []
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      options: [],
      fieldNames: ['city', 'county', 'township', 'village'],
      values: [],
      type: true
    }
  },
  watch: {
    defaultvalue: function(value) {
      this.values = value.filter(ins => {
        return ins !== ''
      })
      this.values.length > 0 && this.setDefault()
    }
  },
  mounted() {
    this.loadfisrtData()
    this.values = [...this.defaultvalue]
  },
  methods: {
    loadfisrtData() {
      axios.get('/dict/nhDictXzq/getList', { params: { pcode: 460000000000 } }).then(res => {
        let arr = res.result
        arr.forEach(element => {
          element.isLeaf = false
        })
        this.options = arr
      })
    },
    onChange(arr) {
      this.values = [...arr]
      let obj = {}
      if (arr.length == 0) {
        obj = null
        this.loadfisrtData()
        this.$emit('onChanged', obj)
        return
      }
      const length = arr.length
      // 取出所得數(shù)組 最后一位;
      const value = arr[length - 1]
      const key = this.fieldNames[length - 1]
      obj[key] = value
      // 返回最后一位對應結(jié)果
      this.$emit('onChanged', obj)
      // 返回對應關(guān)系結(jié)果
      let newObj = {}
      let nameArray = {}
      let keyarr = [...this.fieldNames]
      if (arr[0] == 460300000000 || arr[0] == 460100000000 || arr[0] == 460200000000) {
        this.getCodeName(nameArray, this.options, 0, keyarr, arr)
        // {'cityname':'', 'countyname':'', 'townshipname':'', 'villagename':''}
        keyarr.forEach((ins, index) => {
          newObj[ins] = arr[index]
        })
        arr.length == 4 ? this.$emit('resultCodeArray', { nameArray, newObj }) : this.$emit('resultCodeArray', null)
      } else if (arr[0] == 460400499000) {
        keyarr.splice(1, 2)
        this.getCodeName(nameArray, this.options, 0, keyarr, arr)
        // this.getCodeName(nameArray, this.options, 0, keyarr)
        keyarr.forEach((ins, index) => {
          newObj[ins] = arr[index]
        })
        arr.length == 2 ? this.$emit('resultCodeArray', { nameArray, newObj }) : this.$emit('resultCodeArray', null)
      } else {
        // let keys = ['city', 'township', 'village']
        //{'cityname':'','townshipname':'', 'villagename':''}
        keyarr.splice(1, 1)
        this.getCodeName(nameArray, this.options, 0, keyarr, arr)
        keyarr.forEach((ins, index) => {
          newObj[ins] = arr[index]
        })
        arr.length == 3 ? this.$emit('resultCodeArray', { nameArray, newObj }) : this.$emit('resultCodeArray', null)
      }
    },
    loadData(selectedOptions) {
      const targetOption = selectedOptions[selectedOptions.length - 1]
      if (targetOption.hasChild == 0) {
        return
      }
      this.finaly = false
      targetOption.loading = true
      axios.get('/dict/nhDictXzq/getList', { params: { pcode: targetOption.code } }).then(res => {
        targetOption.loading = false
        let arr = res.result
        arr.forEach(element => {
          element.isLeaf = false
        })
        targetOption.children = arr
        this.options = [...this.options]
      })
    },
    getCodeName(nameArray, parent, index, values, arr) {
      // console.log('parent',parent)
      let node = parent.find(node => {
        return node.code == arr[index]
      })
      if (node) {
        nameArray[values[index] + 'name'] = node['name']
        if ('children' in node) {
          index++
          this.getCodeName(nameArray, node.children, index, values, arr)
        }
      }
    },
    setDefault() {
      //   console.log('訪問的values', this.values)
      //   let promiseArr = []
      //   this.values.forEach(ins => {
      //     promiseArr.push(
      //       new Promise((resolve, reject) => {
      //         axios.get('/dict/nhDictXzq/getList', { params: { pcode: ins } }).then(res => {
      //           resolve(res.result)
      //         })
      //       })
      //     )
      //   })
      //   Promise.all(promiseArr).then(result => {
      //     console.log('result',JSON.stringify(result))
      //     // 先把result的數(shù)據(jù)結(jié)果集組裝
      //     let res = []
      //     this.values.forEach((ins, index) => {
      //       if (index + 1 < this.values.length) {
      //         result.forEach((c, index) => {
      //           let a = c.filter(i => {
      //             return i.code == this.values[index + 1]
      //           })
      //           if (a && a.length > 0) {
      //             a.isLeaf = false
      //             a.loading = false
      //             res.push(a)
      //             // 合并數(shù)組
      //             res = Array.prototype.concat.apply([], res)
      //             res = Array.from(new Set(res))
      //           }
      //         })
      //       }
      //     })
      //     for (var i = res.length; i > 0; i--) {
      //       if (res[i]) {
      //         res[i - 1].children = [res[i]]
      //       }
      //     }
      //     res = res[0]
      //     res.isLeaf = false
      //     res.loading = false
      //     let d = this.options.find(ins => {
      //       return ins.code == this.values[0]
      //     })
      //     d && (d.children = [res])
      //     // 更新dom
      //     this.type = !this.type
      //   })
      const p = this.options.find(ins => {
        return ins.code == this.values[0]
      })
      p &&
        this.setChildren(p, 1, this.values, () => {
          // 更新dom
          this.type = !this.type
        })
    },
    setChildren(parent, index, values, cb) {
      axios.get('/dict/nhDictXzq/getList', { params: { pcode: parent.code } }).then(res => {
        if (res.result.length == 0) {
          cb()
          return
        }
        parent.children = res.result
        res.result.forEach(ins => {
          ins.isLeaf = false
          ins.loading = false
          if (ins.code === values[index]) {
            index++
            this.setChildren(ins, index, values, cb)
          }
        })
      })
    }
  }
}
</script>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容