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

一、看效果:

按住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属性,控制高亮

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/236969.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序嵌套H5

小程序嵌套H5 使用Hbuild x开发H5页面项目里面使用了js-sdk工具包H5发布完成之后生成URL。新建一个小程序空项目&#xff0c;填写小程序的appid。本地调试的时候如果报错无法打开该网页&#xff0c;那么需要勾选先的不校验。发布体验版本需要注意下面的两个配置点。 使用Hbuild…

moviepy基本参数用法大全

阅读本文档的前置说明&#xff1a; 本文档用于讲解Python的moviepy库的自带函数的用法&#xff0c;主要目的是讲一下每个函数的每个参数的含义&#xff0c;无需一开始就全部掌握&#xff0c;粗略看一下就行&#xff0c;可以在后面自己开发过程&#xff0c;遇到不会用的函数再回…

vue模拟el-table演示插槽用法

很多人知道插槽分为三种&#xff0c;但是实际到elementui当中为什么这么用&#xff0c;就一脸懵逼&#xff0c;接下来就跟大家聊一聊插槽在elementui中的应用&#xff0c;并且自己写一个类似el-table的组件 vue的slot分为三种&#xff1a;:匿名插槽&#xff0c;具名插槽&#x…

作业12.11

1 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和密码不匹配&…

《深入理解计算机系统》学习笔记 - 第四课 - 机器级别的程序

Lecture 05 Machine Level Programming I Basics 机器级别的程序 文章目录 Lecture 05 Machine Level Programming I Basics 机器级别的程序intel 处理器的历史和体系结构芯片的构成AMD 公司(Advanced Micro Devices&#xff0c;先进的微型设备) C, 汇编, 机器代码定义汇编/机器…

RocketMQ - Spring Cloud Alibaba RocketMQ

Spring Cloud Stream是Spring Cloud体系内的一个框架&#xff0c;用于构建与共享消息传递系统连接的高度可伸缩的事件驱动微服务&#xff0c;其目的是简化消息业务在Spring Cloud应用中的开发。 Spring Cloud Stream的架构图如下所示&#xff0c;应用程序通过Spring Cloud Str…

Redis基础系列-主从复制

Redis基础系列-主从复制 文章目录 Redis基础系列-主从复制1. 什么是 Redis 主从复制&#xff1f;2. 主从复制有什么好处&#xff1f;3. 如何配置 Redis 主从复制&#xff1f;4. 主从复制的验证4.1 如何查看主从搭建成功4.2 主从常见疑问4.3 主从常见命令 5. 主从复制的原理和工…

2024美赛备战2--模型建立(*****必看****)

建模 美赛涉及的建模知识范围非常广且深&#xff0c;纵观美赛真题不难发现&#xff0c;很多的模型 都是读研或者读博的时候才会真正深入开始研究&#xff0c;因此&#xff0c;对于做建模的同学来说&#xff0c; 是无法在赛前吃透大量模型的。推荐本科生分两个步骤去有效准备比赛…

设计模式——建造者模式(创建型)

引言 生成器模式是一种创建型设计模式&#xff0c; 使你能够分步骤创建复杂对象。 该模式允许你使用相同的创建代码生成不同类型和形式的对象。 问题 假设有这样一个复杂对象&#xff0c; 在对其进行构造时需要对诸多成员变量和嵌套对象进行繁复的初始化工作。 这些初始化代码…

探索Scrapy-spider:构建高效网络爬虫

Spider简介 Scrapy中的Spider是用于定义和执行数据抓取逻辑的核心组件。Spider负责从指定的网站抓取数据&#xff0c;并定义了如何跟踪链接、解析内容以及提取数据的规则。它允许您定制化地指定要抓取的网站、页面和所需的信息。Spider的作用是按照预定的规则爬取网页&#xf…

关于个人职业选择

职业选择&#xff0c;一直是个老生常谈的话题。这并不是一个容易做的决定。 让我们来看看AI怎么说。 首先是方向性的回答&#xff1a; 然后是一些具体的回答 我个人比较倾向于深耕网络安全。这是一个很有趣也是一个持续发展着的领域。 不知道关于这个事情你怎么看&#xff0…

【C++】POCO学习总结(十二):流(文本编解码、数据压缩、文件读写流等)

【C】郭老二博文之&#xff1a;C目录 1、说明 POCO提供了多种流类&#xff0c;与标准c IOStreams兼容。 大多数POCO流类被实现为过滤器&#xff0c;这意味着它们不写入或读取设备&#xff0c;而是从它们连接的另一个流。 2、文本编解码 2.1 说明 POCO提供了用于编码和解码…

【每日一题】最小体力消耗路径

文章目录 Tag题目来源解题思路方法一&#xff1a;二分枚举答案 写在最后 Tag 【二分枚举答案】【图】【2023-12-11】 题目来源 1631. 最小体力消耗路径 解题思路 拿到这个题目&#xff0c;计算从左上角到右下角的最小体力消耗值&#xff0c;有点像 64. 最小路径和。在 64 题…

散点图直方图折线图的替代

散点图直方图折线图的替代 seaborn官网 数据科学数据可视化&#xff0c;散点图 直方图 折线图的新方法 1.hexbinplot https://seaborn.pydata.org/examples/hexbin marginals.html相当于散点图做了聚合/分箱&#xff0c;使数据的分布展示更明显。Library: seaborn 2.瀑布图展示…

Linux 驱动开发需要掌握哪些编程语言和技术?

Linux 驱动开发需要掌握哪些编程语言和技术&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「Linux从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家&#xf…

图论专栏一《图的基础知识》

图论&#xff08;Graph Theory&#xff09;是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形&#xff0c;这种图形通常用来描述某些实体之间的某种特定关系&#xff0c;用点代表实体&#xff0c;用连接两点的线表示两个实体间具有的…

OpenVINS学习2——VIRAL数据集eee01.bag运行

前言 周末休息了两天&#xff0c;接着做上周五那个VIRAL数据集没有运行成功的工作。现在的最新OpenVINS需要重新写配置文件&#xff0c;不像之前那样都写在launch里&#xff0c;因此需要根据数据集情况配置好estimator_config.yaml还有两个标定参数文件。 VIRAL数据集 VIRAL…

从零开始实现神经网络(三)_RNN循环神经网络

参考文章&#xff1a;rnn循环神经网络介绍 循环神经网络 &#xff08;RNN&#xff09; 是一种专门处理序列的神经网络。它们通常用于自然语言处理 &#xff08;NLP&#xff09; 任务&#xff0c;因为它们在处理文本方面很有效。在这篇文章中&#xff0c;我们将探讨什么是 RNN&a…

【简易版】Linux下Protobuf 实现网络版通讯录--C++

一、介绍 该项目的主要目的是用于熟悉protobuf的使用&#xff0c;体验数据在网络中序列化反序列化的形式&#xff0c;并非一个完整的项目。 该通讯录只实现了增加联系人的功能。服务器端接收到请求后会将联系人的信息打印。 二、环境搭建 使用Httplib库&#xff0c;可以快速…

【ClickHouse】ClickHouse与MySQL之间实时同步数据(MySQL引擎),将MySQL数据实时同步到clickhouse

参考1:MySQL(通过该配置实现了实时同步) 参考2:experimental MaterializedMySQL 参考3:[experimental] MaterializedMySQL(包含设置 allow_experimental_database_materialized_mysql) MySQL引擎用于将远程的MySQL服务器中的表映射到ClickHouse中&#xff0c;并允许您对表进行I…