vue2 element el-transfer穿梭框组件支持拖拽及排序 已封装,随取随用

项目场景:

项目中有个功能用到穿梭框组件,新版本需要支持穿梭框组件排序,由于element2版本中的穿梭框组件本身不支持排序功能

在此不仅需要支持随意更换顺序,还支持从一侧拖拽至另一侧,具体功能效果图如下:
在这里插入图片描述
啊啊啊对不住哈哈,GIF过于模糊,自行脑补吧,临时没找到免费的视频转GIF


穿梭框组件封装代码如下

提示:关于拖拽部分代码是基于其他大佬的基础上稍作修改,原博文地址:[https://blog.csdn.net/juvenile_Li/article/details/126886010?spm=1001.2014.3001.5506]

Tips1: 此功能使用到了sortablejs插件,请务必先下载本插件再引用下面的代码,sortablejs安装命令为:npm install sortablejs --save

Tips2: 下面的代码中引入的其他方法请自行根据自己的项目进行修改,比如:错误提示Messagebox

//先看封装好的组件,此处我们是加了弹框的,如果不需要自行修改去掉即可
<template><div class="delete-info-dialog"><el-dialog:title="dialogTitle":visible.sync="tableItemDialogVisible":close-on-click-modal="false":close-on-press-escape="false"width="700px":before-close="handleClose"><div class="info-body"><el-transfer ref="transfer"v-model="visibleValue":data="transferData":titles="transferTitle"target-order="push":props="transferProps"@left-check-change="leftCheckChange"@right-check-change="rightCheckChange"><span slot-scope="{ option }"draggable="!option.disabled"@dragstart="drag($event, option)">{{ option.label }}</span></el-transfer></div><span slot="footer" class="dialog-footer"><el-button type="primary" @click="handleConfirm">确 定</el-button></span></el-dialog></div>
</template><script>
import Sortable from 'sortablejs' //记得安装拖拽组件哦
import cloneDeep from "lodash.clonedeep"; //这个是深拷贝方法,也可以换成自己的,也可以下载lodash,此处为了避免修改父组件传过来的数据
export default {name: "visible-item-table-dialog",props: {//此处是可以随意定义弹框的文字,且有默认值dialogTitle: {type: String,default: '显示列设置'},//此处是可以定义transfer组件的propstransferProps: {type: Object,default: {key: 'key',label: 'label',}},//此处是可以定义transfer组件的titletransferTitle: {type: Array,default: ()=> ['隐藏列', '显示列']},// 穿梭框总数据transferDataList: {type: Array,default: ()=> []},// 右侧显示列,用户已经选好保存过的数据,从父组件传过来回显visibleTableItemList: {type: Array,default: ()=> []},// 默认显示列,如果用户还没设置过则取这个defaultTableItemList: {type: Array,default: ()=> []},// 控制弹框显隐tableItemDialogVisible: {type: Boolean,default: false},},data() {return {visibleValue: [],//显示列表头数据transferData: [], // 穿梭框数据transferLeftCheckData: [], // 左侧选中数据transferRightCheckData: [], // 右侧选中数据draggingKey: '',  // 当前拖拽项}},mounted() {this.transferData = this.transferDataList;this.visibleValue = this.visibleTableItemList.length>0 ?cloneDeep(this.visibleTableItemList) : cloneDeep(this.defaultTableItemList);// 此处加nextTick 为了保证顺利取到refsthis.$nextTick(()=>{const transfer = this.$refs.transfer.$el;const leftPanel = transfer.getElementsByClassName('el-transfer-panel')[0].getElementsByClassName('el-transfer-panel__body')[0]const rightPanel = transfer.getElementsByClassName('el-transfer-panel')[1].getElementsByClassName('el-transfer-panel__body')[0]const rightEl = rightPanel.getElementsByClassName('el-transfer-panel__list')[0]Sortable.create(rightEl, {onEnd: evt => {const { oldIndex, newIndex } = evtconst temp = this.visibleValue[oldIndex]if (!temp || temp === 'undefined') {return} // 解决右边最后一项从右边拖左边,有undefined的问题// this.$set(this.visibleValue, oldIndex, this.visibleValue[newIndex]) //这种赋值方法会导致数据更新视图未更新,排序后顺序展示错乱,强制更新也无效,原博主是这么赋值的,仅供参考// this.$set(this.visibleValue, newIndex, temp)let _arr = this.visibleValue.splice(oldIndex, 1)this.visibleValue.splice(newIndex, 0, _arr[0])}})// 目前只让右侧支持拖拽顺序即可,左侧暂时注释const leftEl = leftPanel.getElementsByClassName('el-transfer-panel__list')[0]Sortable.create(leftEl, {onEnd: evt => {const { oldIndex, newIndex } = evtconst temp = this.transferData[oldIndex]if (!temp || temp === 'undefined') {return} // 解决右边最后一项从左边拖右边,有undefined的问题            let _arr = this.transferData.splice(oldIndex, 1)this.transferData.splice(newIndex, 0, _arr[0])}})// 关于左侧拖拽至右侧的功能,在本项目中暂时无法实现,经检测drag事件未触发(除了本项目外都可),后续再研究^_^leftPanel.ondragover = ev => ev.preventDefault()leftPanel.ondrop = ev => {ev.preventDefault()// 往左拉const index = this.visibleValue.indexOf(this.draggingKey)if (index !== -1) {// 如果当前拉取的是选中数据就将所有选中的数据拉到左边选中框内if (this.transferRightCheckData.indexOf(this.draggingKey) !== -1) {// 此处为多选执行this.transferRightCheckData.reduce((arr, item) => {if (arr.indexOf(item) !== -1) {// 每次计算将相同的删掉arr.splice(arr.indexOf(item), 1)}return arr}, this.visibleValue)this.transferRightCheckData = []// 清除右侧选中的 不然下次向左拉取时会有缓存// 否则就只拉取当前一个} else {this.visibleValue.splice(index, 1)}}}rightPanel.ondragover = ev => ev.preventDefault()rightPanel.ondrop = ev => {ev.preventDefault()if (!this.draggingKey || this.draggingKey === 'undefined') {return} // 解决右边最后一项从左边拖右边,有undefined的问题// 右边框里没有当前key值的时候 向右拉if (this.visibleValue.indexOf(this.draggingKey) === -1) {// 此处为多选执行// 如果当前拉取的是选中数据就将所有选中的数据拉到右边选中框内if (this.transferLeftCheckData.indexOf(this.draggingKey) !== -1) {this.visibleValue =this.visibleValue.concat(this.transferLeftCheckData)this.transferLeftCheckData = [] // 清除左侧选中的  不然下次向右拉取时会有缓存} else {// 否则就只拉取当前一个this.visibleValue.push(this.draggingKey)}}}})},methods: {//关闭弹框handleClose(){this.$emit("handleCloseTableItem");},//点击确定按钮handleConfirm(){if(this.visibleValue.length<=0){this.$message({message: '未选中任何需要显示的数据',type: 'warning'});return;}this.$emit("handleConfirmVisible",this.visibleValue)},drag(ev, option) {// 赋值当前拖拽的唯一标识this.draggingKey = option[this.transferProps.key]},leftCheckChange(val) {// 穿梭框左侧多选选中this.transferLeftCheckData = [...val]},rightCheckChange(val) {// 穿梭框右侧多选选中this.transferRightCheckData = [...val]},},
}
</script><style lang="scss" scoped>
.delete-info-dialog{/deep/ .el-dialog__body{max-height: 400px;overflow-y: auto;}.info-body{color: #909399;padding-top: 20px;padding-bottom: 20px;.success-info{height: 20px;line-height: 20px;}.info-list{.info{padding: 0 10px;line-height: 20px;word-break: break-all;}}}
}
</style>

封装组件的应用:

提示:上面的代码是封装好的支持拖拽的穿梭框,且在弹框内哦,不在弹框内的自己修改下吧O(∩_∩)O哈哈~:

第一步:在需要的页面引入封装好的组件
//此处用Button触发弹框打开,不需要弹框的省略
<el-button @click="tableItemDialogVisible= true">打开封装好的穿梭框组件弹框</el-button><visible-dialog:default-table-item-list="defaultTableItemList":table-item-dialog-visible="tableItemDialogVisible"v-if="tableItemDialogVisible":visible-table-item-list="visibleTableItemList":transfer-data-list="transferDataList":transfer-props="{key: 'property',label: 'label',}"@handleCloseTableItem="handleCloseTableItem"@handleConfirmVisible="handleConfirmVisible"></visible-dialog><script>
import VisibleDialog from "../../../components/visible-dialog/index.vue"; //记得修改地址哦,这里引入的就是上面那个封装好的组件,地址务必改为自己的哈,文件名也记得改为自己的哈
export default {   components: {VisibleDialog },data(){return {               tableItemDialogVisible: true,//显隐弹框defaultTableItemList: ['date', 'invoiceClass', 'invoiceCode', 'invoiceNum', 'isTravel'],//如果visibleTableItemList为空,直接取defaultTableItemList的值,这个逻辑可根据自己需要自行修改transferDataList: [{label: '销售方名称', property: 'salename', align:'left', minWidth: 180},{label: '销售方税号', property: 'saleaxpayerid', align:'left', minWidth: 180},{label: '购买方税号', property: 'buytaxnumber', align:'left', minWidth: 180},{label: '发票日期', property: 'date', minWidth: 120,},{label: '发票类型', property: 'invoiceClass', minWidth: 180,},{label: '发票代码', property: 'invoiceCode', minWidth: 180,},{label: '发票号码', property: 'invoiceNum', minWidth: 180,},{label: '是否差旅', property: 'isTravel', minWidth: 120},],visibleTableItemList: [],//这个数组的数据是从后来请求回来的,用户自己设置好顺序的数据,如果没有设置就会去取defaultTableItemList里面的数据,这个demo中咱们就默认为空,假装用户还没设置过哈}},methods: {//  关闭显示列弹框handleCloseTableItem(){this.tableItemDialogVisible = false;},// 点击弹框的确认按钮事件,array就是用户自己放在右侧排好序的数组,handleConfirmVisible(array){console.log("用户选择好的右侧的数据",array)// 这里就可以向后端发送请求,保存用户排好序的数据了},}}
</script>

结语:

提示:按照上述代码复制到自己项目中即可实现顶部GIF中的功能了,如有问题,欢迎留言交流,欢迎大佬指点。

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

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

相关文章

1-docker安装和配置、虚拟化、配置国内源、镜像操作、容器基本操作(run运行容器、-v目录映射、-p端口映射、容器其他操作)

1 docker和虚拟化 2 docker安装和配置 2.0 docker 中的一些概念 2.1 配置国内源&#xff08;不配也可以&#xff0c;只是会从国外仓库下载&#xff09; 3 镜像操作 4 容器操作 4.1 容器基本操作 4.2 run运行容器 4.3 -v目录映射 4.4 -p端口映射 4.5 容器其他操作 1 docker和虚…

ROS2编译Python节点来发布和订阅的实践《2》

通过熟悉&#xff1a;ROS2对比ROS1的一些变化与优势&#xff08;全新安装ROS2以及编译错误处理&#xff09;《1》 我们大概了解到了ROS2的重新设计带来的巨大优势&#xff0c;最核心的就是去掉了roscore&#xff0c;这样就避免了因为节点管理器崩溃而使整个系统都崩溃的场景出现…

【0基础学Java第十一课】-- 认识异常

11. 认识异常 11.1 异常的概念与体系结构11.1.1 异常的概念11.1.2 异常的体系结构11.1.3 异常的分类 11.2 异常的处理11.2.1 防御式编程11.2.2 异常的抛出 throw11.2.3 异常的捕获异常声明throwstry-catch捕获并处理finally问题&#xff1a;既然 finally 和 try-catch-finally …

【学历是敲门砖】如果你想有个好的起点,不妨冲一冲计算机考研,这本书将会助你一臂之力

目录 计算机考研难点 《计算机考研精炼1000题》揭秘问答 1. 为什么是1000题&#xff1f; 2. 有什么优势&#xff1f; 3. 编写团队水平如何&#xff1f; 4. 题目及解析品质如何&#xff1f;可以试读吗&#xff1f; 购买链接 高质量的学习提升圈子 京东热卖下单链接&…

Mac安装配置typescript及在VSCode上运行ts

一、Mac上安装typescript sudo npm install -g typescript 测试一下&#xff1a;出现Version则证明安装成功 tsc -v 二、在VSCode上运行 新建一个xxx.ts文件&#xff0c;测试能否运行 console.log("helloworld") 运行报错&#xff1a;ts-node: command not…

宅家追剧神器推荐,高亮轻薄投影仪极米Z7X带你开启追剧新体验

周末假期怎么玩&#xff1f;相信有不少朋友已经准备好了出游计划&#xff0c;当然也有很多小伙伴想趁周末在家追追剧、看看电影、玩玩游戏放松一下。那么&#xff0c;今天笔者就给大家带来了一款假期娱乐神器——极米Z7X&#xff0c;无论是出游还是宅家追剧&#xff0c;极米Z7X…

外部 prometheus监控k8s集群资源(pod、CPU、service、namespace、deployment等)

prometheus监控k8s集群资源 一&#xff0c;通过CADvisior 监控pod的资源状态1.1 授权外边用户可以访问prometheus接口。1.2 获取token保存1.3 配置prometheus.yml 启动并查看状态1.4 Grafana 导入仪表盘 二&#xff0c;通过kube-state-metrics 监控k8s资源状态2.1 部署 kube-st…

mybatis 语法使用各种踩坑(持续更新中。。。)

1、大小写命名&#xff1a;这个别说了&#xff0c;都是泪。 2、联表查询查询&#xff0c;多条合成一条&#xff0c;不生效的原因 博主各种检查关联关系和字段大小写&#xff0c;本来是4条数据最后合成一条数据&#xff0c;死活给你直接返回了4条数据&#xff0c;而且每个类似p…

为什么说品牌低价不是一件好事

消费者货比三价为的是买到低价质优的产品&#xff0c;而网络电商平台的公开&#xff0c;也促进了消费者及品牌进行比价&#xff0c;那品牌低价一定就是好事吗&#xff0c;一定会拉高品牌销量吗。其实是不一定的&#xff0c;低价意味着成本的降低&#xff0c;也可能滋生很多产品…

iview table 默认排序字段不高亮解决办法

iview treeSelect 组件封装 1、表格增加排序时触发的方法2、定义三个变量&#xff0c;sortColumnDefaultStyle存放默认的样式&#xff0c;定义页面默认的列以及顺序3、显示的列加上 sortable, 和样式4、使用下面这块代表默认选中5、点击时清除掉默认的排序6、把排序的字段查询时…

软件开发团队如何确保团队成员与项目进度一致?

在软件开发团队中&#xff0c;确保团队成员的利益与项目进度保持一致&#xff0c;可以采取以下措施&#xff1a; 建立基础流程&#xff1a;建立几个最主要的流程&#xff0c;如任务跟踪、开发效率提升、任务完成等&#xff0c;可以帮助小团队从无序逐步进入有序。 关注员工反馈…

CRS工时分析软件:制造业IE改善的秘密武器

当前全球经济危机下&#xff0c;现场改善及控制浪费是制造型企业关注的焦点&#xff0c;生产现场管理的优劣直接体现了企业在行业中的竞争力&#xff0c;也是体现企业盈利的重要环节。掌握生产现场改善的手法和科学识别现场管理中的浪费&#xff0c;最终为企业降低成本、提高效…