vue3中实现el-tree通过ctrl或shift批量选择节点并高亮展示

2023-12-13 03:39:02

一、看效果:

按住ctrl键实现单个多选? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 按住shift实现区间范围多选? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ??

二、代码:

????????vue页面

<template>
  <el-tree
    class="w100%"
    :data="$.treeData"
    ref="treeTableListRef"
    :props="$.defaultProps"
    highlight-current
    :expand-on-click-node="false"
    key="id"
    :default-expand-all="true"
    @node-click="(data, node) => $.tableFieldsNodeClick(data, node, treeTableListRef)"
  >
    <template #default="{ data }">
      <div style="user-select: none">{{ data.name }}</div>
    </template>
  </el-tree>
</template>

<script setup lang="ts">
import { useData } from "./hooks/index";
const treeTableListRef = ref();
let { $data: $ } = useData();
onMounted(() => {});
onBeforeMount(() => {
  window.addEventListener("keydown", handleKeyDown);
  window.addEventListener("keyup", handleKeyUp);
});
// 按下为true
const handleKeyDown = (event: any) => {
  // 代表按下的是ctrl键
  if (event.key == "Control") {
    $.ctrlKeyPressed = true;
  }
  // 代表按下的是shift键
  if (event.key == "Shift") {
    $.shiftKeyPressed = true;
  }
};
// 释放为false
const handleKeyUp = (event: any) => {
  // 代表按下的是ctrl键
  if (event.key == "Control") {
    $.ctrlKeyPressed = false;
  }
  // 代表按下的是shift键
  if (event.key == "Shift") {
    $.shiftKeyPressed = false;
  }
};
</script>

<style scoped lang="scss">
</style>

????????引入的hooks文件,index.ts

export function useData() {
    const $data: any = reactive({
        ctrlKeyPressed: false,
        shiftKeyPressed: false,
        shiftKeyFelid: [],
        defaultProps: {
            children: "children",
            label: "name",
        },
        treeData: [
            {
                name: '一级1',
                id: 1,
                children: [{
                    name: '二级1',
                    id: 2,
                    children: [{
                        name: '三级1',
                        id: 2,
                    }, {
                        name: '三级2',
                        id: 3,
                    }, {
                        name: '三级3',
                        id: 4,
                    }, {
                        name: '三级4',
                        id: 5,
                    }, {
                        name: '三级5',
                        id: 6,
                    }]
                }, {
                    name: '二级2',
                    id: 3,
                }, {
                    name: '二级3',
                    id: 4,
                }, {
                    name: '二级4',
                    id: 5,
                }, {
                    name: '二级5',
                    id: 6,
                }]
            }, {
                name: '一级2',
                id: 7,
                children: [{
                    name: '二级1',
                    id: 8,
                }, {
                    name: '二级2',
                    id: 9,
                }, {
                    name: '二级3',
                    id: 10,
                }, {
                    name: '二级4',
                    id: 11,
                }, {
                    name: '二级5',
                    id: 12,
                }]
            }],
        selectNodes: []
    })
    // 节点选中事件
    $data.tableFieldsNodeClick = (nodeData: any, node: any, treeTableListRef: any) => {
        const nodes = treeTableListRef.store._getAllNodes();//所有node节点
        const ishas = $data.selectNodes.includes(node.id)
        // 递归遍历节点数组进行ID存放
        function addSelectId(arr: any) {
            for (const item of arr) {
                $data.selectNodes.push(item.id)
                if (Array.isArray(item.children) && item.children.length) {
                    addSelectId(item.children)
                }
            }
        }
        // 递归遍历删除节点id
        function delSelectId(arr: any) {
            for (const item of arr) {
                const index = $data.selectNodes.findIndex((x: any) => x == item.id);
                $data.selectNodes.splice(index, 1);
                if (Array.isArray(item.children) && item.children.length) {
                    delSelectId(item.children);
                }
            }
        }
        // 按住了ctrl键,可以进行单个多选
        if ($data.ctrlKeyPressed) {
            // 如果为true代表当前选中的节点已存在
            if (ishas) {
                // 查找当前选中的节点的索引
                const index = $data.selectNodes.findIndex((x: any) => x == node.id);
                // 删除父节点
                $data.selectNodes.splice(index, 1);
                // 删除子节点
                if (Array.isArray(node.childNodes) && node.childNodes.length) {
                    deleteSelectId(node.childNodes);
                }
            } else {
                // 否则当前选中的节点不存在,就加入到已选节点数组序列
                $data.selectNodes.push(node.id)
                // 防止选中的是父节点,就需要递归将子节点加入
                if (Array.isArray(node.childNodes) && node.childNodes.length) {
                    addSelectId(node.childNodes);
                }
            }
            node.isCurrent = !node.isCurrent;
            // 按下了shift键,可以进行范围多选
        } else if ($data.shiftKeyPressed) {
            // 先清空
            $data.selectNodes = []
            // 将当前节点放入
            $data.selectNodes.push(node.id)
            $data.shiftKeyFelid.push(node.id);
            if ($data.shiftKeyFelid.length > 1) {
                // 首索引
                const sIndex = nodes.findIndex((x: any) => x.id == $data.shiftKeyFelid[0])
                // 尾索引
                const eIndex = nodes.findIndex((x: any) => x.id == $data.shiftKeyFelid[$data.shiftKeyFelid.length - 1]);
                // 根据首尾索引,存入中间节点
                const s = sIndex < eIndex ? sIndex : eIndex //取小值当开头索引
                const e = sIndex < eIndex ? eIndex : sIndex//取大值当结尾索引
                for (let i = s; i < e; i++) {
                    // 放入该区间节点id
                    $data.selectNodes.push(nodes[i].id);
                }
            }
        } else {
            // 否则就是单机选择
            $data.shiftKeyFelid = [];
            $data.selectNodes = [];
            $data.selectNodes = [node.id];
        }
        // 下面是对已选中的节点,进行高亮展示
        // 通过控制elementui中节点上的isCurrent属性
        // isCurrent为true是高亮,否则取消高亮
        for (const item of nodes) {
            if ($data.selectNodes.includes(item.id)) {
                item.isCurrent = true;
            } else {
                item.isCurrent = false;
            }
        }
    };
    return {
        $data: $data
    }
}

三、注意:

? ? ? ? 1、重点是要获取当前所选节点数组

????????2、通过循环节点数组来更新nodes节点中isCurrent属性,控制高亮

文章来源:https://blog.csdn.net/qq_41579104/article/details/134881042
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。