el-tree结合el-tree-transfer实现穿梭框里展示树形数据

参考文章:我把他的弹框单拉出来一个独立文件作为组件方便使用,遇到一些问题记录一下。
在这里插入图片描述

testComponet.vue

<template><div class="per_container"><div class="per_con_left"><div class="per_con_title">未选</div><div class="check_all"><el-checkbox:indeterminate="config.left.isIndeterminate"v-model="config.left.checkAll"@change="handleCheckAll($event, 'left')">全选/全不选</el-checkbox></div><div class="tree"><el-treeref="treeLeft":data="treeDataArr":props="propsDefault"node-key="id"show-checkbox:filter-node-method="filterNodeLeft"@check-change="handleCheckChange('left')"/></div></div><div class="operation"><el-button type="primary" @click="toRight()">移入<i class="el-icon-d-arrow-right"></i></el-button><el-button type="primary" icon="el-icon-d-arrow-left" @click="toLeft()">移除</el-button></div><div class="per_con_right"><div class="per_con_title">已选</div><div class="check_all"><el-checkbox:indeterminate="config.right.isIndeterminate"v-model="config.right.checkAll"@change="handleCheckAll($event, 'right')">全选/全不选</el-checkbox></div><div class="tree"><el-treeref="treeRight":data="treeDataArr":props="propsDefault"node-key="id"show-checkbox:filter-node-method="filterNodeRight"@check-change="handleCheckChange('right')"/></div></div></div>
</template>
<script>
export default {props: ['treeData'],mounted() {this.treeDataArr = this.treeData;this.allParentKeys = this.treeDataArr.map((item) => {return item.id;});if (this.$refs.treeLeft && this.$refs.treeRight) {this.$nextTick(() => {this.setTreeFilter();});}},created() {// this.treeDataArr = this.treeData;// this.allParentKeys = this.treeDataArr.map((item) => {//     return item.id;// });// if (this.$refs.treeLeft && this.$refs.treeRight) {//     this.$nextTick(() => {//         this.setTreeFilter();//     });// }},  data() {return {propsDefault: {label: "name"},isIndeterminateL: false,isIndeterminateR: false,checkAllLeft: false,checkAllRight: false,treeDataArr: [],checkedKeys: [],halfCheckedKeys: [],checkedNodes: [],config: {left: {isIndeterminate: false,checkAll: false,ref: "treeLeft"},right: {isIndeterminate: false,checkAll: false,ref: "treeRight"}}};},methods: {setTreeFilter() {this.$refs.treeLeft.filter();this.$refs.treeRight.filter();},toLeft() {this.checkedKeys = this.$refs.treeRight.getCheckedKeys();this.halfCheckedKeys = this.$refs.treeRight.getHalfCheckedKeys();this.settreeDataArr(this.treeDataArr, false);this.setTreeFilter();this.$refs.treeLeft.setCheckedKeys(this.checkedKeys);this.$refs.treeRight.setCheckedKeys([]);},toRight() {this.checkedKeys = this.$refs.treeLeft.getCheckedKeys();this.halfCheckedKeys = this.$refs.treeLeft.getHalfCheckedKeys();this.settreeDataArr(this.treeDataArr, true);this.setTreeFilter();this.$refs.treeRight.setCheckedKeys(this.checkedKeys);this.$refs.treeLeft.setCheckedKeys([]);},filterNodeLeft(value, data) {console.log('filterNodeLeft',data);return !data.selected;},filterNodeRight(value, data) {console.log('filterNodeRight',data);return data.selected;},// 递归设置数据选中状态settreeDataArr(tree, type) {const setTree = (treeDataArr) => {treeDataArr.forEach((item, index) => {if (this.checkedKeys.includes(item.id)) {treeDataArr[index].selected = type;}if (item.children && item.children.length) {setTree(item.children);// 判断半选框是否需要移动if (this.halfCheckedKeys.includes(item.id)) {if (type) {treeDataArr[index].selected = type;} else {const target = treeDataArr[index].children.find((it) => {return it.selected;});if (!target) {treeDataArr[index].selected = type;}}}}});};setTree(tree);},submitEdit() {this.$emit("permissionData", this.treeDataArr);},// 勾选树结构时判断是否勾选上面的全选handleCheckChange(type) {this.checkedNodes = this.$refs[this.config[type].ref].getCheckedNodes();const pIds = this.checkedNodes.filter((item) => {return !item.pId;});if (!pIds.length) {this.config[type].checkAll = false;this.config[type].isIndeterminate = false;return;}if (pIds.length === this.allParentKeys.length) {this.config[type].checkAll = true;this.config[type].isIndeterminate = false;} else {this.config[type].isIndeterminate = true;this.config[type].checkAll = false;}},// 全选handleCheckAll(value, type) {const keys = value? this.treeDataArr.map((item) => {return item.id;}): [];this.$refs[this.config[type].ref].setCheckedKeys(keys, false);}}
};
</script>
<style lang="scss" scoped>
.per_container {display: flex;height: 500px;justify-content: space-between;align-items: center;
}
.per_con_left,
.per_con_right {width: 45%;height: 100%;
}
.operation {display: flex;flex-direction: column;align-items: center;justify-content: center;padding: 20px;
}
.operation .el-button {margin-left: 0;margin-bottom: 10px;
}
.per_con_title {height: 42px;line-height: 26px;border-radius: 8px 8px 0 0;padding: 8px;align-self: stretch;background: #f2f6f9;font-size: 16px;box-sizing: border-box;border: 1px solid #d8d8d8;font-weight: 700;text-align: left;
}
.check_all {height: 42px;line-height: 42px;padding: 0 5px;border: 1px solid #d8d8d8;border-top: none;text-align: left;
}
.tree {height: calc(100% - 82px);border: 1px solid #d8d8d8;border-top: none;overflow: auto;
}
</style>

思路
(1)思路二:利用elementUI的filter API对选中节点进行筛选,左侧筛选出未选中的,右侧筛选出选中的,用的还是同一棵树,用一个属性来区分是否选择,好处是子节点选中,父节点会跟随保存,不用重新构建树结构。
(2)通过监听treeData值变化,调用setTreeFilter也就是this.$refs.treeLeft.filter(); this.$refs.treeRight.filter();
里的filter 方法,filter 是 el-tree 组件用于动态过滤树节点,配合 filter-node-method 属性可以实现节点过滤,自定义左右侧树过滤的规则分别是是filterNodeLeft(value, data) { return !data.selected;},filterNodeRight(value, data) {return data.selected;},是否被选中(左移右移来设置selected属性)

testIndex.vue

<template><div><!-- 其他页面内容 --><TestComponent :treeData="myTreeData" /></div>
</template><script>
import TestComponent from '@/views/test/test.vue';export default {components: {TestComponent},data() {return {myTreeData: [// 这里放置你的树形数据{id: 1,name: '父节点1',children: [{id: 2,name: '子节点1'}]}]};},// ... existing code ...
};
</script>

关于监听treeData变化后给树赋数据这里遇到问题:我把原文监听treeData对树进行初始化一开始写在created里,导致左右都有树,然后改为mounted就没有这个问题。
原因:(操作DOM元素用mounted
依赖 DOM 元素 : setTreeFilter 方法可能依赖于 this.$refs.treeLeftthis.$refs.treeRight 这两个 DOM 引用。在 created 阶段,DOM 元素还未挂载, this.$refs 无法正确获取到对应的 DOM 元素,从而导致过滤逻辑无法正常执行。而在 mounted 阶段,DOM 元素已经挂载完成, this.$refs 可以正常获取到对应的 DOM 元素,过滤逻辑就能正常工作了。

treeData: {handler(val) {this.treeDataArr = val;this.allParentKeys = this.treeDataArr.map((item) => {return item.id;});if (this.$refs.treeLeft && this.$refs.treeRight) {this.$nextTick(() => {this.setTreeFilter();});}},deep: true,},
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。原文链接:https://blog.csdn.net/Error_ABC/article/details/136877442

在这里插入图片描述

 created() {// this.treeDataArr = this.treeData;// this.allParentKeys = this.treeDataArr.map((item) => {//     return item.id;// });// if (this.$refs.treeLeft && this.$refs.treeRight) {//     this.$nextTick(() => {//         this.setTreeFilter();//     });// }},  

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go 后端中双 token 的实现模板

下面是一个典型的 Go 后端双 Token 认证机制 实现模板&#xff0c;使用 Gin 框架 JWT Redis&#xff0c;结构清晰、可拓展&#xff0c;适合实战开发。 项目结构建议 /utils├── jwt.go // Access & Refresh token 的生成和解析├── claims.go // 从请求…

Typescript学习教程,从入门到精通,TypeScript 对象语法知识点及案例代码(7)

TypeScript 对象语法知识点及案例代码 TypeScript 是 JavaScript 的超集&#xff0c;提供了静态类型检查和其他增强功能。在 TypeScript 中&#xff0c;对象是面向对象编程&#xff08;OOP&#xff09;的基础。 一、对象概述 在 TypeScript 中&#xff0c;对象是属性的集合&a…

应用BERT-GCN跨模态情绪分析:贸易缓和与金价波动的AI归因

本文运用AI量化分析框架&#xff0c;结合市场情绪因子、宏观经济指标及技术面信号&#xff0c;对黄金与美元指数的联动关系进行解析&#xff0c;揭示本轮贵金属回调的深层驱动因素。 周三&#xff0c;现货黄金价格单日跌幅达2.1%&#xff0c;盘中触及3167.94美元/盎司关键价位&…

命令行登录 MySQL 报 Segmentation fault 故障解决

问题描述&#xff1a;对 mysql8.0.35 源码进行 make&#xff0c;由于一开始因为yum源问题少安装依赖库 库&#xff0c;在链接时遇到错误 undefined reference to&#xff0c;后来安装了相关依赖库&#xff0c;再次 make 成功。于是将 mysqld 启动&#xff0c;再用 mysql -u roo…

Axure设计数字乡村可视化大屏:构建乡村数据全景图

今天&#xff0c;让我们一同深入了解由Axure设计的数字乡村可视化大屏&#xff0c;看看它如何通过精心的布局和多样化的图表类型&#xff0c;将乡村的各类数据以直观、易懂的方式呈现出来&#xff0c;为乡村管理者提供有力的数据支持。 原型效果预览链接&#xff1a;Axure数字乡…

3D个人简历网站 4.小岛

1.模型素材 在Sketchfab上下载狐狸岛模型&#xff0c;然后转换为素材资源asset&#xff0c;嫌麻烦直接在网盘链接下载素材&#xff0c; Fox’s islandshttps://sketchfab.com/3d-models/foxs-islands-163b68e09fcc47618450150be7785907https://gltf.pmnd.rs/ 素材夸克网盘&a…

智能开发工具PhpStorm v2025.1——增强AI辅助编码功能

PhpStorm是一个轻量级且便捷的PHP IDE&#xff0c;其旨在提高用户效率&#xff0c;可深刻理解用户的编码&#xff0c;提供智能代码补全&#xff0c;快速导航以及即时错误检查。可随时帮助用户对其编码进行调整&#xff0c;运行单元测试或者提供可视化debug功能。 立即获取PhpS…

Spark 的运行模式(--master) 和 部署方式(--deploy-mode)

Spark 的 运行模式&#xff08;--master&#xff09; 和 部署方式&#xff08;--deploy-mode&#xff09;&#xff0c;两者的核心区别在于 资源调度范围 和 Driver 进程的位置。 一、核心概念对比 维度--master&#xff08;运行模式&#xff09;--deploy-mode&#xff08;部署…

sqli—labs第八关——布尔盲注

一&#xff1a;确定注入类型 按照我们之前的步骤来 输入 ?id1 and 11-- ?id1 and 12-- 界面正常 第二行界面异常空白 所以注入类型为单引号闭合型 二&#xff1a; 布尔盲注 1.判断是否使用条件 &#xff08;1&#xff09;&#xff1a;存在注入但不会直接显示查询结果 …

ARP 原理总结

&#x1f310; 一、ARP 原理总结 ARP&#xff08;Address Resolution Protocol&#xff09;是用于通过 IP 地址解析 MAC 地址的协议&#xff0c;工作在 链路层 与 网络层之间&#xff08;OSI 模型的第三层与第二层之间&#xff09;。 &#x1f501; ARP通信过程&#xff1a; …

SpringCloud——EureKa

目录 1.前言 1.微服务拆分及远程调用 3.EureKa注册中心 远程调用的问题 eureka原理 搭建EureKaServer 服务注册 服务发现 1.前言 分布式架构&#xff1a;根据业务功能对系统进行拆分&#xff0c;每个业务模块作为独立项目开发&#xff0c;称为服务。 优点&#xff1a; 降…

机顶盒刷机笔记

疑难杂症解决 hitool线刷网口不通tftp超时--》关闭防火墙cm201-2卡刷所有包提示失败abort install--》找个卡刷包只刷fastboot分区再卡刷就能通过了&#xff08;cm201救砖包 (M8273版子&#xff09;&#xff09; 刷机工具 海兔烧录工具HiTool-STB-5.3.12工具&#xff0c;需要…

Linux动静态库制作与原理

什么是库 库是写好的现有的&#xff0c;成熟的&#xff0c;可以复用的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个人的代码都从零开始&#xff0c;因此库的存在意义非同寻常。 本质上来说库是一种可执行代码的二进制形式&#xff0c;可以被操作系统…

如何通过小智AI制作会说话的机器人玩具?

一、硬件准备与组装 1. 核心硬件选择 主控芯片&#xff1a;选择支持无线网络连接、音频处理和可编程接口的嵌入式开发板 音频模块&#xff1a;配备拾音麦克风与小型扬声器&#xff0c;确保语音输入/输出功能 显示模块&#xff1a;选择适配的交互显示屏用于可视化反馈 扩展模…

如何控制邮件发送频率避免打扰用户

一、用户行为 监测用户与邮件的互动数据&#xff0c;如打开率、点击率下滑或退订申请增多&#xff0c;可能是发送频率过高的警示信号。利用邮件营销平台的分析工具&#xff0c;识别这些指标的变动趋势&#xff0c;为调整提供依据。 二、行业特性与受众差异 不同行业用户对邮…

定积分的“偶倍奇零”性质及其使用条件

定积分的“偶倍奇零”性质是针对对称区间上的奇偶函数积分的重要简化方法。以下是其核心内容和应用要点&#xff1a; ​一、基本性质 ​偶函数&#xff08;偶倍&#xff09;​ 若 f(x) 在 [−a,a] 上为偶函数&#xff08;即 f(−x)f(x)&#xff09;&#xff0c;则&#xff1a; …

如何在 Windows 11 或 10 上安装 Fliqlo 时钟屏保

了解如何在 Windows 11 或 10 上安装 Fliqlo,为您的 PC 或笔记本电脑屏幕添加一个翻转时钟屏保以显示时间。 Fliqlo 是一款适用于 Windows 和 macOS 平台的免费时钟屏保。它也适用于移动设备,但仅限于 iPhone 和 iPad。Fliqlo 的主要功能是在用户不活动时在 PC 或笔记本电脑…

【C/C++】C++并发编程:std::async与std::thread深度对比

文章目录 C并发编程&#xff1a;std::async与std::thread深度对比1 核心设计目的以及区别2 详细对比分析3 代码对比示例4 适用场景建议5 总结 C并发编程&#xff1a;std::async与std::thread深度对比 在 C 中&#xff0c;std::async 和 std::thread 都是用于并发编程的工具&am…

Axure疑难杂症:垂直菜单展开与收回(4大核心问题与专家级解决方案)

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢!如有帮助请订阅专栏! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:垂直菜单展开与收回 主要内容:超长菜单实现、展开与收回bug解释、Axure9版本限制等问题解…

ASIC和FPGA,到底应该选择哪个?

ASIC和FPGA各有优缺点。 ASIC针对特定需求&#xff0c;具有高性能、低功耗和低成本&#xff08;在大规模量产时&#xff09;&#xff1b;但设计周期长、成本高、风险大。FPGA则适合快速原型验证和中小批量应用&#xff0c;开发周期短&#xff0c;灵活性高&#xff0c;适合初创企…