vue实现自定义树形穿梭框功能

需求:

我们在开发过程中,会遇到需要将一个数据选择做成穿梭框,但是要求穿梭框左侧为树形结构、右侧为无层级结构的数据展示,ElementUI自身无法在穿梭框中添加树形结构,网上搜到了大佬封装的插件但是对于右侧的无树形结构一点还是不太满足。以下是我们简单的封装写的组件可以实现此功能

在这里插入图片描述

1,封装的treeTransfetr组件如下:
<template><div class="treeTransfer"><!-- 左边 --><div class="leftTree"><div class="list"><div class="left_lowline"><div class="leftcheck_con"><el-checkbox v-model="checkedLeft" :disabled="leftTreeData.length < 1" label="" size="large"style="margin-right: 12px" @change="leftAllCheck" /><p class="left_title">{{ props.title[0] }}</p></div><div>{{ leftOperation.length }}/{{ leftAllselectIdarry.length }}</div></div><el-tree ref="leftTreeRef" :data="leftTreeData" show-checkboxnode-key="id" :props="props.defaultProps" v-slot="{ node, data }" accordion:check-strictly="true"@check="onCheckLeft" default-expand-all><div>{{ data.label }}</div></el-tree></div></div><!-- 中间按钮 --><div class="btnDiv"><div class="mg10"><el-button @click="toRight()" icon="ele-Right" type="primary"  circle :disabled="leftOperation.length < 1"/></div><div class="mg10"><el-button @click="toLeft()" icon="ele-Back" type="primary" circle :disabled="rightOperation.length < 1"/></div></div><!-- 右边 --><div class="rightTree"><div class="list"><div class="left_lowline"><div class="leftcheck_con"><el-checkbox v-model="checkedRight" :disabled="rightTreeData.length < 1" label="" size="large"style="margin-right: 12px" @change="rightAllCheck" /><p class="left_title">{{ props.title[1] }}</p></div><div>{{ rightOperation.length }}/{{ rightAllselectIdarry.length }}</div></div><el-tree ref="rightTreeRef" :data="rightTreeData" show-checkbox node-key="id":props="props.defaultProps" v-slot="{ node, data }" accordion :check-strictly="true"@check="onCheckRight" default-expand-all><div>{{ data.label }}</div></el-tree></div></div></div></template><script setup lang="ts">import { ref, onMounted, watch, nextTick } from 'vue';import lodash from 'lodash-es'const props = defineProps(['fromData', 'toData', 'defaultProps', 'title', 'visible']);const checkedLeft = ref(false)const checkedRight = ref(false)const leftOperation = ref<any[]>([])const rightOperation = ref<any[]>([])// 定义emitconst emits = defineEmits(['addStaffchange']);const leftTreeRef = ref();const rightTreeRef = ref();// 左侧数据const leftTreeData = ref([] as any);// 右侧数据const rightTreeData = ref([] as any);// 左侧可以选中id集合const leftAllselectIdarry = ref([] as any)// 右侧可以选中id集合const rightAllselectIdarry = ref([] as any)watch(props,newVal => {leftTreeData.value = lodash.cloneDeep(newVal.fromData)rightTreeData.value = lodash.cloneDeep(newVal.toData)// 获取左侧的全选中的idleftAllselectIdarry.value = getAllIds(leftTreeData.value, [])if (newVal.visible) {checkedLeft.value = falsecheckedRight.value = falseleftOperation.value = []rightOperation.value = []nextTick(() => {leftTreeRef?.value.setCheckedKeys([])})}},{ immediate: true })defineExpose({leftTreeData,rightTreeData})onMounted(() => {})// 去右边const toRight = async () => {const leftTree = leftTreeRef.value;if (!leftTree) {return}const leftNodes = leftTree.getCheckedNodes(false, false)const checkedKeys = leftTree.getCheckedKeys(false)const rightTree = rightTreeRef.valueconst newArr = rightTreeData.value.concat(leftNodes)let obj = {};let peon = newArr.reduce((cur,next) => {obj[next['id']] ? "" : obj[next['id']] = true && cur.push(next);return cur;},[]) //设置cur默认类型为数组,并且初始值为空的数组const getnewleftArry = peon.map(item => {return {id: item.id,label: item.label,pid: item.pid,children: [],}})rightTreeData.value = getnewleftArryleftOperation.value = leftTreeRef.value?.getCheckedKeys(false)emits('addStaffchange', checkedKeys)setTimeout(() => {rightTree?.setCheckedNodes(leftNodes);rightOperation.value = rightTreeRef.value?.getCheckedKeys(false)rightAllcheckChange()}, 500)};// 去左边const toLeft = async () => {const rightTree = rightTreeRef.valueif (!rightTree) {return}const checkedKeys = rightTree.getCheckedKeys(false)for(var i=0; i<rightTreeData.value.length;i++){if(checkedKeys.includes(rightTreeData.value[i].id)){rightTreeData.value.splice(i,1)i-=1}}rightOperation.value = rightTree?.getCheckedKeys(false)if (rightTreeData.value && rightTreeData.value.length === 0) {checkedRight.value = false}emits('addStaffchange', getAllIds(rightTreeData.value, []))};//左侧选中const onCheckLeft = () => {leftOperation.value = leftTreeRef.value?.getCheckedKeys(false)if (leftOperation.value.length === leftAllselectIdarry.value.length) {checkedLeft.value = true} else {checkedLeft.value = false}}// 右侧选中const onCheckRight = () => {rightOperation.value = rightTreeRef.value?.getCheckedKeys(false)rightAllselectIdarry.value.length = getAllIds(rightTreeData.value, []).lengthrightAllcheckChange()}// 右侧是否全选获取function rightAllcheckChange () {rightAllselectIdarry.value.length = getAllIds(rightTreeData.value, []).lengthif (rightOperation.value.length === rightAllselectIdarry.value.length) {checkedRight.value = true} else {checkedRight.value = false}return checkedRight.value}// 左侧全选中值 const leftAllCheck = () => {if (checkedLeft.value) {leftTreeRef.value.setCheckedKeys(getAllIds(leftTreeData.value, []))checkedLeft.value = true;} else {leftTreeRef.value.setCheckedKeys([])checkedLeft.value = false}leftOperation.value = leftTreeRef.value?.getCheckedKeys(false)}// 右侧全选中值 const rightAllCheck = () => {if (checkedRight.value) {rightTreeRef.value.setCheckedKeys(getAllIds(rightTreeData.value, []))checkedRight.value = true} else {rightTreeRef.value.setCheckedKeys([])checkedRight.value = false}rightOperation.value = rightTreeRef.value?.getCheckedKeys(false)}// 递归获取所有id数据function getAllIds(tree, result) {//遍历树获取id数组for (const i in tree) {if (!tree[i].disabled) {result.push(tree[i].id); // 遍历项目满足条件后的操作}if (tree[i].children) {// 存在子节点就递归getAllIds(tree[i].children, result);}}return result;}</script><style scoped lang="scss">.treeTransfer {display: flex;justify-content: center;.el-tree {overflow: auto;max-height: 360px;}.leftTree {border: 1px solid #ebeef5;width: 40%;height: calc(100% - 60px);overflow: auto;}.left_lowline {display: flex;align-items: center;justify-content: space-between;background: #f5f7fa;padding: 0 23px 0 10px;.leftcheck_con {display: flex;align-items: center;}}.btnDiv {width: 20%;height: calc(100% - 60px);text-align: center;margin: auto 0;line-height: 40px;position: relative;}.rightTree {width: 40%;height: calc(100% - 60px);}}</style>
2,具体使用如下
<treeTransfetr ref="treeTransferRef" :fromData="fromData":toData="toData":visible="visible":defaultProps="transferProps" @addStaffchange="addStaffchange" :title="['筛选结果', '添加人员']"></treeTransfetr>let treeTransferRef = ref(); // 树形穿梭框
let fromData = ref([{id: "1",pid: 0,    //自定义pid的参数名,默认为"pid" 必填:falselabel: "张三-D1-DM",disabled: false,children: [{id: "1-1",pid: "1",label: "李四-D1-TL",disabled: false,children: []},{id: "1-2",pid: "1",label: "王五-D2-TL",disabled: false,children: [{id: "1-2-1",pid: "1-2",children: [],label: "赵六-D3-TL",disabled: true,},{id: "1-2-2",pid: "1-2",children: [],label: "李明-D4-TL",disabled: false,},{id: "1-2-3",pid: "1-2",children: [],label: "王三明-D5-TL",disabled: false,}]}]}
]); // 树形数据
let toData = ref([]); // 选中的ids数据
const transferProps = ref({label: 'label',children: 'children',disabled: 'disabled',
});

如果我们想要用插件实现,推荐使用el-tree-transfer

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

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

相关文章

Socket网络编程(一)——网络通信入门基本概念

目录 网络通信基本概念什么是网络&#xff1f;网络通信的基本架构什么是网络编程?7层网络模型-OSI模型什么是Socket&#xff1f;Socket的作用和组成Socket传输原理Socket与TCP、UDP的关系CS模型(Client-Server Application)报文段牛刀小试&#xff08;TCP消息发送与接收&#…

vulnhub-----Hackademic靶机

文章目录 1.C段扫描2.端口扫描3.服务扫描4.web分析5.sql注入6.目录扫描7.写马php反弹shell木马 8.反弹shell9.内核提权 1.C段扫描 kali:192.168.9.27 靶机&#xff1a;192.168.9.25 ┌──(root㉿kali)-[~] └─# arp-scan -l Interface: eth0,…

11.以太网交换机工作原理

目录 一、以太网协议二、以太网交换机原理三、交换机常见问题思考四、同网段数据通信全过程五、跨网段数据通信全过程六、关键知识七、调试命令 前言&#xff1a;在网络中传输数据时需要遵循一些标准&#xff0c;以太网协议定义了数据帧在以太网上的传输标准&#xff0c;了解以…

苹果iOS群控系统开发常见功能及其代码解析!

随着移动互联网的快速发展&#xff0c;iOS设备因其良好的用户体验和丰富的应用生态&#xff0c;受到了广大用户的喜爱&#xff0c;苹果iOS群控系统&#xff0c;即可以同时对多台iOS设备进行集中控制和管理的系统&#xff0c;逐渐成为了开发者、测试人员以及企业管理的有力工具。…

解析馆藏文物预防性保护:监测平台与数据传输系统概述

1&#xff09;文物预防性保护监测平台概述 文物预防性保护监测与调控系统是文物环境监测必不可少的关键组成部分之一,在项目实施中,将充分利用前沿物联网技术&#xff0c;如无线网络、低功耗设计、高精度传感器来实现文物保存环境的实时监测与数据分析。此外&#xff0c;还将通…

php基础学习之错误处理(其二)

在实际应用中&#xff0c;开发者当然不希望把自己开发的程序的错误暴露给用户&#xff0c;一方面会动摇客户对己方的信心&#xff0c;另一方面容易被攻击者抓住漏洞实施攻击&#xff0c;同时开发者本身需要及时收集错误&#xff0c;因此需要合理的设置错误显示与记录错误日志 一…

SpringMVC 学习(七)之报文信息转换器 HttpMessageConverter

目录 1 HttpMessageConverter 介绍 2 RequestBody 注解 3 ResponseBody 注解 4 RequestEntity 5 ResponseEntity 6 RestController 注解 1 HttpMessageConverter 介绍 HttpMessageConverter 报文信息转换器&#xff0c;将请求报文&#xff08;如JSON、XML、HTML等&#x…

android移动应用开发答案第二版,Kafka是如何实现高性能的

面试官&#xff1a;说说什么是 UI 线程&#xff1f; A&#xff1a;就是用来刷新 UI 所在的线程嘛 面试官&#xff1a;多说点 A&#xff1a;UI 是单线程刷新的&#xff0c;如果多个线程可以刷新 UI 就无所谓是不是 UI 线程了&#xff0c;单线程的好处是&#xff0c;UI 框架里…

一个Web3项目的收官之作,必然是友好的用户界面(Web3项目三实战之四)

正如标题所述,一个对用户体验友好的应用,总是会赢得用户大加赞赏,这是毋庸置疑的。 甭管是web2,亦或是已悄然而至的Web3,能有一个外观优美、用户体验效果佳的的界面,那么,这个应用无疑是个成功的案例。 诚然,Web3项目虽然核心是智能合约攥写,但用户界面也是一个DApp不…

程序员的金三银四求职宝典

随着春天的脚步渐近&#xff0c;对于许多程序员来说&#xff0c;一年中最繁忙、最重要的面试季节也随之而来。金三银四&#xff0c;即三月和四月&#xff0c;被广大程序员视为求职的黄金时期。在这两个月里&#xff0c;各大公司纷纷开放招聘&#xff0c;求职者们则通过一轮又一…

性能】JDK和Jmeter的安装与配置

一、JDK环境配置 1. 下载JDK 官网下载地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html 选择对应系统的安装包&#xff0c;下载后安装&#xff0c;安装中记录JDK安装的地址&#xff0c;之后一直点击下一…

VuePress + GitHub 搭建个人博客踩坑记录

最近想给我教练搭个网站,本来选的是 VuePress 框架,也折腾完了,起码是搭建出来了,踩的坑也都总结好了 但是最近发现了一个更简洁的模板: VuePress-theme-hope ,所以最终网站使用的样式是这个 不过我觉得这里面踩坑的记录应该还是有些价值的,分享出来,看看能不能帮到一些小伙伴~…

大数据分析案例-基于SVM支持向量机算法构建手机价格分类预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Softmax 回归 + 损失函数 + 图片分类数据集【动手学深度学习v2】李沐动手学深度学习课程笔记

目录 Softmax回归 损失函数 图片分类数据集 Softmax回归从零开始实现 Softmax回归简洁实现 Softmax回归 回归和分类的区别 回归问题举例上节课的预测房价问题&#xff0c;分类问题就是对样本进行分类 回归和分类的具体区别 假设真实的类别为第i个类别&#xff08;值为1&#x…

RK3568 Android12 适配抖音 各大APP

RK3568 Android12 适配抖音 各大APP SOC RK3568 system:Android 12 平台要适配抖音和各大APP 平台首先打开抖音发现摄像头预览尺寸不对只存在右上角,我将抖音APP装在手机上预览,发现是全屏 一开始浏览各大博客 给出的解决方法是修改framework 设置为全屏显示: framewo…

android移动应用开发基础答案,安卓工程师面试题

一线企业的app都是多线程和多进程的&#xff0c;而Android进程间通信机制就是Binder&#xff0c;原生的线程间通信则是Handler&#xff0c;Binder和Handler是了解安卓运行机制必须要掌握的一个知识点&#xff0c;更是一线企业面试必问的知识点&#xff01; 以下几道就是大厂关于…

谷歌seo推广秒收录怎么做?

谷歌SEO推广秒收录想要做到&#xff0c;可以利用我们光算科技独家技术&#xff0c;GSI快速收录&#xff0c;通过技术手段和操作&#xff0c;帮你的网站快速被谷歌发现和记录 这项技术具体核心就是GPC爬虫池系统&#xff0c;这个系统是专门研究谷歌搜索引擎优化的规律和算法创造…

韦东山嵌入式Liunx入门驱动开发三

文章目录 一、GPIO和Pinctrl子系统的使用1-1 Pinctrl子系统1-2 GPIO子系统1-3 基于GPIO子系统的LED驱动程序 本人学习完韦老师的视频&#xff0c;因此来复习巩固&#xff0c;写以笔记记之。 韦老师的课比较难&#xff0c;第一遍不知道在说什么&#xff0c;但是坚持看完一遍&…

SemiDrive E3 MCAL 开发系列(3)– Wdg 模块的使用

一、 概述 本文将会介绍 SemiDrive E3 MCAL Wdg 模块的基本配置&#xff0c;并且会结合实际操作的介绍&#xff0c;帮助新手快速了解并掌握这个模块的使用&#xff0c;文中的 MCAL 是基于 PTG3.0 的版本&#xff0c;开发板是官方的 E3640 网关板。 二、 Wdg 模块的主要配置 …

buuctf_misc_九连环

题目&#xff1a;&#xff08;一张123456cry.jpg&#xff09; 这个先直接上kali&#xff0c;图片已改名cry.jpg 在上一篇&#xff0c;我留存了kali文件夹下有"叉"打不开的问题&#xff0c;经查阅&#xff0c;已解决&#xff1a; http://t.csdnimg.cn/bgv4T 输入&a…