序文
作中では、組織情報やディレクトリなどのツリー構造のデータを表示する場面に遭遇しますが、elementUI での el-select と el-tree ツリー コントロールの組み合わせは少し面倒で複雑なので、一般的にはパーソナライズされた Ant Design Vue のtreeselect を使用します。目的の効果を達成するためのコンポーネント。データ量が少なければそのままコンポーネントを利用できますが、データ量が多すぎるとページの描画や読み込み速度が遅くなってしまいます。たとえば、ある銀行の支店には 3,600 を超える部門および組織情報があるため、データは遅延ロードすることしかできません。さらに、上にスライドしてから下にスワイプするとデータが更新され、下にスライドしてから上にスワイプするとさらに多くのデータが読み込まれ、あいまい検索機能も利用できます。
ボディコード
最初のステップは、パブリック サブコンポーネント BranchTreeSelect.vue を作成することです。
<template v-slot>
<a-tree-select
v-model="currentBranchNumber"
tree-data-simple-mode
style="width:100%"
:dropdown-style="{maxHeight: '400px', overflow: 'auto'}"
:tree-data="branchTreeData"
allow-clear
:show-search="true"
:load-data="onLoadTreeData"
:search-value="searchValue"
placeholder="请选择机构或分行"
@search="onSearch"
@clear="clearSelect"
@focus="focusSelect"
/>
</template>
<script>
import { getCurrentBranchAndChildrenBranchInfos, getCurrentBranchInfo } from '@/api/user'
export default {
name: 'BranchTreeSelect',
props: {
branchNumber: {
type: String
}
},
data() {
return {
branchTreeData: [],
searchValue: '',
currentBranchNumber: '',
allowSearchFlag: true
}
},
watch: {
'currentBranchNumber': {
handler(val) {
if (val) {
this.$emit('setBranchNumber', this.currentBranchNumber.toString().split(':')[0])
} else {
this.$emit('setBranchNumber', '')
}
}
}
},
created() {
this.initValue(this.branchNumber) // 初始化机构树
},
methods: {
initValue(val) {
this.currentBranchNumber = val
},
onSearch(val) { // 可以模糊检索, 需要后端支持
// 是否允许进行检索, 上一次检索数据还没渲染好不允许检索
if (this.allowSearchFlag && !isNaN(parseInt(val)) && isFinite(val) && val.length > 2) { // 机构号至少3位数字时才可以检索
this.allowSearchFlag = false
getCurrentBranchInfo(val).then(res => {
this.branchTreeData = []
const treeArray = []
res.forEach(function(item) {
const node = {
id: item.branchNumber,
pId: item.upperBranch,
value: (item.branchNumber + ':' + item.branchName),
title: (item.branchNumber + ':' + item.branchName),
isLeaf: item.isLeafBranch !== 'N'
}
treeArray.push(node)
})
this.branchTreeData = this.branchTreeData.concat(treeArray) // 拼接数组数据
this.allowSearchFlag = true
})
}
},
focusSelect() { // 聚焦的时候查询数据, 机构id传空查询根机构以及根机构下直接子机构。如果branchTreeData有数据, 则不再查询后端数据。如果生成树结构数据过程中也不会查询后端数据。
if (this.branchTreeData.join() === '' && this.allowSearchFlag) {
getCurrentBranchAndChildrenBranchInfos('').then(res => {
this.setTreeNode('', res)
})
}
},
clearSelect() { // 清空选中的机构, 则重新向后端查询根机构以及根机构下直接子机构
this.branchTreeData = []
getCurrentBranchAndChildrenBranchInfos('').then(res => {
this.setTreeNode('', res)
})
},
setTreeNode(parentId, dataList) { // 根据后端返回的结果生成树结构
this.allowSearchFlag = false // 生成树结构的过程中不允许检索, 因为会导致数据的错漏...期待后续优化
const treeArray = []
dataList.forEach(function(item) {
const node = {
id: item.branchNumber,
pId: parentId,
value: (item.branchNumber + ':' + item.branchName),
title: (item.branchNumber + ':' + item.branchName),
isLeaf: item.isLeafBranch !== 'N'
}
treeArray.push(node)
})
const tempArr = this.branchTreeData.concat(treeArray)
const newArr = []
for (const i in tempArr) {
if (!newArr.some(res => res.id === tempArr[i].id)) {
newArr.push(tempArr[i])
}
}
this.branchTreeData = newArr
this.allowSearchFlag = true
},
onLoadTreeData(treeNode) { // 加载更多数据
return new Promise(resolve => {
const { id } = treeNode.dataRef
setTimeout(() => {
getCurrentBranchAndChildrenBranchInfos(id).then(res => {
this.setTreeNode(id, res)
resolve()
})
}, 300)
})
}
}
}
</script>
<style scoped>
</style>
2 番目のステップは、親コンポーネントで public 子コンポーネントを呼び出すことです。
<branch-tree-select :branch-number="formData.branchNumber" @setBranchNumber="setBranchNumber" />
export default {
import BranchTreeSelect from '@/components/BranchTreeSelect'
components: {
BranchTreeSelect
},
methods: {
setBranchNumber(val) {
// val是子组件选中值后传过来的机构号
}
}
}
ご質問がございましたら、以下にメッセージを残してください。各項目を注意深く確認し、返信するよう努めます。ご覧いただきありがとうございます^^