在树形组件显示复选框的情况下,check-strictly遵循父子不互相关联,通过在非叶子节点插槽增加按钮实现全选功能,从而实现树形组件单选情况下增加了全选功能。
## 实现效果
[demo](https://ztrainwilliams.github.io/formula-rule-editor/#/select-tree)
## 需求前情
在树形组件支持的原有模式下,要么是遵循父子互相关联,则无法单选一个非叶子节点(父级);要么无法遵循父子不互相关联,此模式下便是单选模式,当遇到大量选择的时候,需要逐个选择则无法满足快捷使用。当前的组件原有设计并没有完美的兼容模式,但是业务提出了这个需求,我们只要思考解决方案。
## 方案确认
1. 确认单选模式,开启check-strictly
2. 增加一个可全选的入口
3. 全选情况下可反选
## 代码实现
全选、反选实现
``` vue
<template>
<el-tree-v2
ref="treeV2Ref"
v-loading="loading"
:data="treeData"
:props="props.props"
:check-strictly="props.checkStrictly"
:showCheckbox="props.showCheckbox"
@check-change="treeChange"
>
<template #default="{ node, data }">
<span class="prefix" :class="{ 'is-leaf': node.isLeaf }">
<el-button
v-if="data.children && data.children.length"
link
type="primary"
@click.stop="nodeClick(node, data)"
:disabled="node.disabled"
>
<slot name="select-all-title">
[全选]
</slot>
</el-button>
{{ node.label }}
</span>
</template>
</el-tree-v2>
</template>
<script setup>
import { uniq, without } from 'lodash-es';
// 获取全部子节点
/**
* @description:
* @param {Array} list
* @param {Array} result
* @return {Array}
*/
const getDeepChildren = (list, result = []) => {
list.forEach((item) => {
if (item.children && item.children.length > 0) {
getDeepChildren(item.children, result);
}
!item.disabled && result.push(item.key);
});
return result;
};
/**
* @description: 判断存在未勾选
* @param {Array} checkedKeys
* @param {Array} childrens
* @return {Boolean}
*/
const isCheckAllChildren = (checkedKeys, childrens) => {
const setCheckedKeys = new Set();
checkedKeys.forEach((v) => setCheckedKeys.add(v));
for (let i = 0; i < childrens.length; i += 1) {
if (!setCheckedKeys.has(childrens[i])) {
return false;
}
}
return true;
};
/**
* @description: 全选点击
* @param {*} node
* @return {*}
*/
const nodeClick = (node) => {
if (node.disabled) return false;
const checkedKeys = treeV2Ref.value?.getCheckedKeys();
const childrens = [...getDeepChildren(node.children ?? []), node.key]; // 全选-包含本级
nextTick(() => {
let list = [];
if (isCheckAllChildren(checkedKeys, childrens)) {
// 反选
list = without(checkedKeys, ...childrens);
treeV2Ref.value.setCheckedKeys();
} else {
list = uniq([...checkedKeys, ...childrens]);
}
treeV2Ref.value.setCheckedKeys(list);
update(list);
});
};
</script>
```
## END
如果你有更好的建议和解决方案,可以多多探讨。
[组件treeV2](https://github.com/ZTrainWilliams/formula-rule-editor/tree/master/src/components/treeV2/index.vue)