前言
- 在網(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>
