自定义树,实现全选功能
父组件示例
<template>
<tree-select-with-check-all v-model="selectedValues" :treeData="treeData" />
</template>
<script setup lang="ts">
import TreeSelectWithCheckAll from "./TreeSelectWithCheckAll.vue";
import { ref } from "vue";
const selectedValues = ref<(string | number)[]>([12]);
const treeData = [
{
value: 1,
label: "节点1",
children: [
{ value: 11, label: "节点1-1" },
{ value: 12, label: "节点1-2" },
],
},
{ value: 2, label: "节点2", children: [{ value: 21, label: "节点2-1" }] },
];
</script>
子组件 TreeSelectWithCheckAll.vue
<template>
<el-tree-select
v-model="internalValue"
:data="treeData"
multiple
show-checkbox
collapse-tags
collapse-tags-tooltip
:max-collapse-tags="1"
style="width: 300px"
:props="{ children: 'children', label: 'label', value: 'value' }"
>
<template #header>
<el-checkbox
:model-value="checkAll"
:indeterminate="indeterminate"
@change="onCheckAllChange"
>
全选
</el-checkbox>
</template>
</el-tree-select>
</template>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
interface TreeNode {
value: string | number;
label: string;
children?: TreeNode[];
}
const props = defineProps<{
modelValue: (string | number)[];
treeData: TreeNode[];
}>();
const emit = defineEmits<{
(e: "update:modelValue", val: (string | number)[]): void;
}>();
const internalValue = ref<(string | number)[]>([...props.modelValue]);
// 获取所有叶子节点
const getLeafValues = (nodes: TreeNode[]): (string | number)[] => {
let leaves: (string | number)[] = [];
nodes.forEach((node) => {
if (node.children && node.children.length > 0) {
leaves.push(...getLeafValues(node.children));
} else {
leaves.push(node.value);
}
});
return leaves;
};
const leafValues = computed(() => getLeafValues(props.treeData));
// 全选状态
const checkAll = ref(false);
const indeterminate = ref(false);
// 点击全选
const onCheckAllChange = (val: boolean) => {
internalValue.value = val ? [...leafValues.value] : [];
};
// watch 内部值变化,更新全选 / 半选状态
watch(
internalValue,
(val) => {
const selectedSet = new Set(val);
const allSelected = leafValues.value.every((v) => selectedSet.has(v));
const noneSelected = leafValues.value.every((v) => !selectedSet.has(v));
checkAll.value = allSelected;
indeterminate.value = !allSelected && !noneSelected;
emit("update:modelValue", val);
},
{ deep: true, immediate: true }
);
</script>