1. 设置check-strictly
可选择各层级且父子数关联
<!-- 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: {
// 树结构数据
treeData: {
type: Array,
default() {
return [];
},
},
// 默认选中的节点key
defaultKey: {
type: Array,
default() {
return [];
},
}
},
data() {
return {
isShowSelect: false, // 是否显示树状选择器
options: [],
returnDatas: [], // 返回给父组件数组对象
selectVal: []
}
},
created () {
},
watch: {
// 隐藏select自带的下拉框
isShowSelect() {
this.$refs.select.blur();
}
},
methods: {
// 节点被点击
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() // 所有被选中的节点的 key 所组成的数组数据
this.options = checkedKeys.map(item => {
const node = this.$refs.tree.getNode(item) // 所有被选中的节点对应的node
if (node.level === 1) { // 第一层
node.hide = false
} else {
node.hide = !node.parent.indeterminate && node.parent.checked
}
// 设置option选项
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()
},
// 如果不是全选中为父级添加半选状态,如果子集全选后,父级也要全选
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 // 子集是否是全选,如果子集全选,则半选状态为假
fnode.checked = true
}
if (fnode.parent) {
this.setParentChecked(fnode.parent)
}
},
// 将子节点全选中
setChildChecked(childNodes) {
if (childNodes && childNodes.length > 0) {
childNodes.map(k => {
k.checked = true
this.setChildChecked(this.$refs.tree.getNode(k).childNodes)
})
}
},
// 如果取消子节点的选中,设置父级节点选中状态
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 // 子集是否是全选,如果子集全选,则半选状态为假
fnode.checked = isAllChecked
if (fnode.parent) { // 如果有父节点,则需要去判断父节点是否选中
this.deleteParentChecked(fnode.parent, true)
}
}
},
// 删除子节点的勾选状态
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 选项
removeTag(val) {
this.$refs.tree.setChecked(val, false); // 设置节点的勾选状态为未选中
this.nodeClick(val)
},
// 清空所有勾选
clearSelectedNodes() {
this.selectVal = this.returnDatas = []
this.$refs.tree.setCheckedKeys([])
},
// 下拉框关闭
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. 增加虚拟滚动
- 安装
vue-virtual-scroll-list
$ yarn add vue-virtual-scroll-list
-
在
tree-virtual-node.vue
中增加以下方法,否则点击收起箭头无效果 -
将
el-tree
改为virtual-tree
,其余参数都一致
<!-- 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>
网友评论