1. 設(shè)置check-strictly
可選擇各層級(jí)且父子數(shù)關(guān)聯(lián)
<!-- child.vue -->
<template>
<div class="select-tree-container">
<el-popover
placement="bottom-start"
popper-class="select-tree-popper"
v-model="isShowSelect"
@hide="closePopver"
>
<el-tree
ref="tree"
:data="treeData"
node-key="id"
default-expand-all
:expand-on-click-node="false"
check-strictly
check-on-click-node
show-checkbox
:default-expanded-keys="defaultKey"
@check="nodeClick"
></el-tree>
<el-select
slot="reference"
ref="select"
v-model="selectVal"
multiple
@remove-tag="removeTag"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-popover>
</div>
</template>
<script>
export default {
name: 'SelectTree',
props: {
// 樹(shù)結(jié)構(gòu)數(shù)據(jù)
treeData: {
type: Array,
default() {
return [];
},
},
// 默認(rèn)選中的節(jié)點(diǎn)key
defaultKey: {
type: Array,
default() {
return [];
},
}
},
data() {
return {
isShowSelect: false, // 是否顯示樹(shù)狀選擇器
options: [],
returnDatas: [], // 返回給父組件數(shù)組對(duì)象
selectVal: []
}
},
created () {
},
watch: {
// 隱藏select自帶的下拉框
isShowSelect() {
this.$refs.select.blur();
}
},
methods: {
// 節(jié)點(diǎn)被點(diǎn)擊
nodeClick(v) {
const anode = this.$refs.tree.getNode(v)
if (anode.checked) {
this.setParentChecked(anode.parent)
this.setChildChecked(anode.childNodes)
} else {
this.deleteParentChecked(anode.parent)
this.deleteChildChecked(anode.childNodes)
}
var checkedKeys = this.$refs.tree.getCheckedKeys() // 所有被選中的節(jié)點(diǎn)的 key 所組成的數(shù)組數(shù)據(jù)
this.options = checkedKeys.map(item => {
const node = this.$refs.tree.getNode(item) // 所有被選中的節(jié)點(diǎn)對(duì)應(yīng)的node
if (node.level === 1) { // 第一層
node.hide = false
} else {
node.hide = !node.parent.indeterminate && node.parent.checked
}
// 設(shè)置option選項(xiàng)
return {
...node,
label: node.label,
value: node.key
}
})
this.returnDatas = this.selectVal = this.options.filter(o => !o.indeterminate && !o.hide).map(item => item.value)
this.closePopver()
},
// 如果不是全選中為父級(jí)添加半選狀態(tài)憔晒,如果子集全選后锣尉,父級(jí)也要全選
setParentChecked(parent) {
const fnode = this.$refs.tree.getNode(parent)
// 子集是否是全選
const isAllChecked = fnode.childNodes.every(k => k.checked && k.indeterminate === false)
if (!fnode.isLeaf) {
fnode.indeterminate = !isAllChecked // 子集是否是全選卿城,如果子集全選粮彤,則半選狀態(tài)為假
fnode.checked = true
}
if (fnode.parent) {
this.setParentChecked(fnode.parent)
}
},
// 將子節(jié)點(diǎn)全選中
setChildChecked(childNodes) {
if (childNodes && childNodes.length > 0) {
childNodes.map(k => {
k.checked = true
this.setChildChecked(this.$refs.tree.getNode(k).childNodes)
})
}
},
// 如果取消子節(jié)點(diǎn)的選中,設(shè)置父級(jí)節(jié)點(diǎn)選中狀態(tài)
deleteParentChecked(parent, d = false) {
const fnode = this.$refs.tree.getNode(parent)
const isAllChecked = fnode.childNodes.some(k => d ? (k.checked || k.indeterminate) : k.checked) // 子集是否是全選
if (!fnode.isLeaf) {
fnode.indeterminate = isAllChecked // 子集是否是全選,如果子集全選黎侈,則半選狀態(tài)為假
fnode.checked = isAllChecked
if (fnode.parent) { // 如果有父節(jié)點(diǎn)筹陵,則需要去判斷父節(jié)點(diǎn)是否選中
this.deleteParentChecked(fnode.parent, true)
}
}
},
// 刪除子節(jié)點(diǎn)的勾選狀態(tài)
deleteChildChecked(childNodes) {
if (childNodes && childNodes.length > 0) {
childNodes.map(k => {
k.indeterminate = false
k.checked = false
this.deleteChildChecked(this.$refs.tree.getNode(k).childNodes)
})
}
},
// 刪除任一 select 選項(xiàng)
removeTag(val) {
this.$refs.tree.setChecked(val, false); // 設(shè)置節(jié)點(diǎn)的勾選狀態(tài)為未選中
this.nodeClick(val)
},
// 清空所有勾選
clearSelectedNodes() {
this.selectVal = this.returnDatas = []
this.$refs.tree.setCheckedKeys([])
},
// 下拉框關(guān)閉
closePopver() {
this.$emit("get:value", this.selectVal, this.returnDatas);
}
}
};
</script>
<style lang="scss">
.select-tree-container {
.el-select {
width: 280px;
}
}
.select-tree-popper {
box-sizing: border-box;
width: 280px;
}
</style>
<template>
<div class="app-container">
<select-tree
:tree-data="treeData"
:defaultKey="defaultCheckedKeys"
@get:value="getTreeVal"
/>
</div>
</template>
<script>
import SelectTree from '@/components/SelectTree.vue';
export default {
components: { SelectTree },
name: "App",
data() {
return {
treeData: [
{
id: 1,
label: "水果",
children: [
{
id: 4,
label: '香蕉',
children: [
{ id: 41, label: '小香蕉' },
{ id: 42, label: '大香蕉' },
]
},
{
id: 5,
label: '圣女果',
children: [
{ id: 51, label: '小圣果' },
{ id: 52, label: '大圣果' },
]
}
]
},
{
id: 2,
label: "食物",
children: [
{ id: 6, label: '龍蝦' },
{ id: 7, label: '螃蟹' }
]
}
],
defaultCheckedKeys: []
}
},
methods: {
getTreeVal(val, data) {
// console.log(val, data);
}
}
};
</script>
2. 增加虛擬滾動(dòng)
- 安裝
vue-virtual-scroll-list
$ yarn add vue-virtual-scroll-list
-
在
tree-virtual-node.vue
中增加以下方法,否則點(diǎn)擊收起箭頭無(wú)效果 將
el-tree
改為virtual-tree
彪蓬,其余參數(shù)都一致
<!-- child.vue -->
<template>
<div class="select-tree-container">
...
<virtual-tree
ref="tree"
:data="treeData"
node-key="id"
default-expand-all
:expand-on-click-node="false"
check-strictly
check-on-click-node
show-checkbox
:default-expanded-keys="defaultKey"
@check="nodeClick"
></virtual-tree>
...
</div>
</template>
<script>
import VirtualTree from './virtualNodeTree/tree'
export default {
name: 'SelectTree',
components: { VirtualTree }
}
</script>