效果
原理分析
- 从后端获取数据后,判断当前节点是否勾选,从而判断是否勾选子节点
- 勾选当前节点时,子节点均勾选
全勾选
与半勾选
与不勾选
的样式处理全勾选
和全取消勾选
的逻辑- 筛选出半勾选的节点
定义变量
import {
computed, nextTick, reactive, ref} from 'vue';
import {
tree} from "./tree.js";
// 默认节点
const tableData = reactive([
{
id: '节点1', hasChildren: true}, {
id: '节点2', hasChildren: true},
{
id: '节点3', hasChildren: true}, {
id: '节点4', hasChildren: true},
]);
const treeTableRef = ref(); // 表格实例
const selections = ref([]); // 勾选节点
const childrenNodes = reactive({
}); // 全部子节点
const isSelectedAll = ref(false); // 是否勾选全部
定义是否勾选全部子节点函数
/**
* 勾选子节点
* @param id
* @param selected
*/
const selectedChildren = (id, selected) => {
(childrenNodes[id] || []).forEach(row => {
treeTableRef.value.toggleRowSelection(row, selected);
if (id !== row.id) selectedChildren(row.id, selected);
});
}
单个节点勾选函数
/**
* 单个节点勾选
* @param selection 选中节点集合
* @param row 当前节点
*/
const select = (selection, row) => {
nextTick(() => {
// 是否勾选当前节点下全部子节点
selectedChildren(row.id, selection.some(d => d.id === row.id));
});
}
从后端获取节点数据
/**
* 加载子节点
* @param row 当前节点
* @param treeNode 节点状态
* @param resolve 渲染子集函数
*/
const load = (row, treeNode, resolve) => {
setTimeout(() => {
childrenNodes[row.id] = (tree[row.id] || []).map(d => ({
...d, parentId: row.id}));
resolve(childrenNodes[row.id]);
// 判断当前节点是否选中,选中则自动勾选子节点
nextTick(() => select(selections.value, row));
}, 100);
}
全勾选、全取消勾选函数和勾选监听
/**
* 全选节点勾选
* @param selection 选中节点集合
*/
const selectAll = (selection) => {
isSelectedAll.value = !isSelectedAll.value;
treeTableRef.value.data.forEach(row => {
// 默认数据的勾选
treeTableRef.value.toggleRowSelection(row, isSelectedAll.value);
// 是否勾选全部节点下全部子节点
selectedChildren(row.id, isSelectedAll.value);
});
}
/**
* 监听节点选择事件
* @param selection 选中节点集合
*/
const selectionChange = (selection) => {
selections.value = selection;
// 勾选的节点数量为0时,设置勾选全部的状态为false
nextTick(() => ((selection.length === 0) && (isSelectedAll.value = false)));
}
表头Checkbox选中样式
/**
* 表格头选中状态
* @type {ComputedRef<string>} 样式选择器名称
*/
const headerRowClassName = computed(() => {
let count = tableData.length;
for (const key in childrenNodes) {
count += (childrenNodes[key] || []).length;
}
return (count === selections.value.length || selections.value.length === 0) ? '' : 'half-checked';
})
定义当前节点样式选择器
/**
* 定义表格行样式选择器
* @param row 当前节点
* @param rowIndex 当前节点索引
* @returns {string} 样式选择器名称
*/
const rowClassName = ({
row, rowIndex}) => {
if (selections.value.length === 0) return '';
const selectedNodeFlags = []; // 存储节点的状态
/**
* 筛选子节点勾选状态
* @param item 当前节点
*/
const filterSelectedChildrenNodeFlags = (item) => {
(childrenNodes[item.id] || []).forEach(node => {
// 避免死循环
if (item.id
本文含有隐藏内容,请 开通VIP 后查看