树结构,多选,全选功能

47 阅读1分钟

自定义树,实现全选功能

父组件示例

<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>