elementplus结合sortablejs做出表格可拖拽效果的组件
1.安装npm install sortablejs2.在src下新建可复用的组合式函数文件夹composablessrc/composables/useSortableDrag.jsimport { ref, onMounted, onBeforeUnmount, nextTick } from vue import Sortable from sortablejs /** * 拖拽排序配置选项 * typedef {Object} SortableOptions * property {string} handle - 拖拽手柄选择器默认为 .drag-handle * property {number} animation - 动画持续时间ms默认为 150 * property {string} easing - 缓动函数默认为 cubic-bezier(0.25, 0.46, 0.45, 0.94) * property {number} scrollThreshold - 触发滚动的边缘距离px默认为 80 * property {number} scrollSpeed - 滚动速度默认为 15 * property {boolean} autoScroll - 是否启用自动滚动默认为 true * property {Function} onSort - 排序完成后的回调函数 * property {Function} onStart - 拖拽开始时的回调函数 * property {Function} onEnd - 拖拽结束时的回调函数 * property {Function} onMove - 拖拽移动时的回调函数 */ /** * 拖拽排序组合式函数 * param {string|Ref} tableRef - 表格引用 * param {RefArray} dataList - 数据列表引用 * param {SortableOptions} options - 配置选项 * returns {Object} 拖拽控制方法 */ export function useSortableDrag(tableRef, dataList, options {}) { const { handle .drag-handle, animation 150, easing cubic-bezier(0.25, 0.46, 0.45, 0.94), scrollThreshold 80, scrollSpeed 15, autoScroll true, onSort null, onStart null, onEnd null, onMove null } options let sortableInstance null let autoScrollTimer null let autoScrollDirection 0 // 0: 停止, 1: 向下, -1: 向上 const isDragging ref(false) // 停止自动滚动 const stopAutoScroll () { if (autoScrollTimer) { clearInterval(autoScrollTimer) autoScrollTimer null } autoScrollDirection 0 } // 启动自动滚动 const startAutoScroll (tableWrapper) { if (!autoScroll || autoScrollTimer) return autoScrollTimer setInterval(() { if (autoScrollDirection 0 || !tableWrapper) return const scrollTop tableWrapper.scrollTop const maxScrollTop tableWrapper.scrollHeight - tableWrapper.clientHeight let newScrollTop scrollTop autoScrollDirection * scrollSpeed // 限制滚动范围 if (newScrollTop 0) { newScrollTop 0 autoScrollDirection 0 stopAutoScroll() } else if (newScrollTop maxScrollTop) { newScrollTop maxScrollTop autoScrollDirection 0 stopAutoScroll() } tableWrapper.scrollTop newScrollTop }, 16) // 约 60fps } // 获取表格包装器 const getTableWrapper () { if (!tableRef.value) return null // 兼容不同的表格组件 if (tableRef.value.$el) { return tableRef.value.$el.querySelector(.el-table__body-wrapper) } return tableRef.value.querySelector?.(.el-table__body-wrapper) || null } // 获取表格主体 const getTableBody () { const wrapper getTableWrapper() return wrapper?.querySelector(tbody) || null } // 初始化拖拽 const initSortable () { if (!tableRef.value) { console.warn(useSortableDrag: tableRef is not ready) return } const tableBody getTableBody() const tableWrapper getTableWrapper() if (!tableBody || !tableWrapper) { console.warn(useSortableDrag: table body or wrapper not found) return } // 如果已经存在实例先销毁 destroySortable() sortableInstance Sortable.create(tableBody, { handle, animation, easing, scroll: false, // 禁用默认滚动使用自定义滚动 onStart: (evt) { isDragging.value true document.body.style.cursor grabbing if (onStart) onStart(evt) }, onMove: (evt) { if (!autoScroll) { if (onMove) onMove(evt) return } const { originalEvent } evt const clientY originalEvent.clientY if (!tableWrapper) return const rect tableWrapper.getBoundingClientRect() const relativeY clientY - rect.top // 检查是否在边缘区域 if (relativeY scrollThreshold) { // 向上滚动 autoScrollDirection -1 startAutoScroll(tableWrapper) } else if (relativeY rect.height - scrollThreshold) { // 向下滚动 autoScrollDirection 1 startAutoScroll(tableWrapper) } else { // 停止滚动 autoScrollDirection 0 stopAutoScroll() } if (onMove) onMove(evt) }, onEnd: (evt) { // 拖拽结束时停止自动滚动 stopAutoScroll() document.body.style.cursor isDragging.value false const { oldIndex, newIndex } evt if (oldIndex newIndex) { if (onEnd) onEnd(evt) return } // 移动数据 const [movedItem] dataList.value.splice(oldIndex, 1) dataList.value.splice(newIndex, 0, movedItem) if (onSort) onSort(evt, movedItem, oldIndex, newIndex) if (onEnd) onEnd(evt) } }) } // 销毁拖拽实例 const destroySortable () { if (sortableInstance) { sortableInstance.destroy() sortableInstance null } stopAutoScroll() } // 更新拖拽实例当数据变化时重新初始化 const refreshSortable () { nextTick(() { initSortable() }) } // 禁用拖拽 const disableSortable () { if (sortableInstance) { sortableInstance.option(disabled, true) } } // 启用拖拽 const enableSortable () { if (sortableInstance) { sortableInstance.option(disabled, false) } } // 设置拖拽手柄选择器 const setHandle (selector) { if (sortableInstance) { sortableInstance.option(handle, selector) } } // 生命周期钩子 onMounted(() { // 延迟初始化确保 DOM 已渲染 setTimeout(initSortable, 100) }) onBeforeUnmount(() { destroySortable() }) return { initSortable, destroySortable, refreshSortable, disableSortable, enableSortable, setHandle, isDragging, stopAutoScroll } }3.在需要用到的地方添加el-table-column aligncenter fixed width40 label template #default el-icon classdrag-handle stylecursor: grab; color: #909399 Operation / /el-icon /template /el-table-column // 使用拖拽排序功能 const { refreshSortable } useSortableDrag(tableRef, chainTableList, { handle: .drag-handle, animation: 150, autoScroll: true, scrollThreshold: 80, scrollSpeed: 15, disabled: false }) async function getData() { …… refreshSortable() }

相关新闻

CTFSHOW-WEB(萌新18-22)

CTFSHOW-WEB(萌新18-22)

web18 1.本题比上一题多过滤了一个file,但是和上一题的思路一样:Nginx 访问日志路径 /var/log/nginx/access.log 不包含 php、file 这两个被拦截字符串,所以上一题的日志投毒方法依然可以直接使用。 2.按照上面的思路,我们直接进…

2026/10/11 6:47:16 阅读更多 →
腾讯云OpenClaw智能开发平台一键部署与优化指南

腾讯云OpenClaw智能开发平台一键部署与优化指南

1. OpenClaw与Clawdbot项目概述 OpenClaw(又称Clawdbot)是腾讯云生态中快速崛起的一站式智能开发平台,它通过模块化技能包(Skills)和可视化编排能力,让开发者能够快速构建AI应用。这个平台最吸引人的特点在…

2026/10/10 22:18:40 阅读更多 →
低代码平台选型:交付能力与可视化开发的平衡之道

低代码平台选型:交付能力与可视化开发的平衡之道

1. 低代码平台的本质矛盾:交付能力与可视化开发的博弈 在2023年企业数字化转型调研报告中,一个令人震惊的数据是:采用低代码平台的企业中,有67%的项目最终未能达到预期业务目标。而在这67%的失败案例中,89%的问题根源并…

2026/10/11 10:57:40 阅读更多 →

最新新闻

n8n实战:用可视化节点搭建自动化工作流,告别脚本泥潭

n8n实战:用可视化节点搭建自动化工作流,告别脚本泥潭

第一次接触 n8n,是因为被一堆手工报表逼到崩溃。那阵子我每天早上的固定动作是打开三个后台系统,把销售数据、库存余量和客服反馈分别导出,再手动整理成一张总表发出去,整个过程雷打不动要花掉二十分钟,错一位小数都不…

2026/10/11 12:46:35 阅读更多 →
C# WinForms工控上位机界面开发:从串口数据到自定义控件的实战方案

C# WinForms工控上位机界面开发:从串口数据到自定义控件的实战方案

简介:《C# WinForm高级设计(工控与界面)》是一份面向C#桌面开发者与工控行业从业者的进阶学习资源,聚焦WinForm在工业监控与用户界面设计中的实践应用,系统讲解控件布局、事件处理、数据绑定、多线程通信及硬件数据交换…

2026/10/11 12:46:35 阅读更多 →
AI时代网站建设新标准:从传统SEO到GEO的转型实践

AI时代网站建设新标准:从传统SEO到GEO的转型实践

1. AI时代网站流量格局变了,传统SEO正在失效这两年做网站的人应该都有明显感觉:以前辛辛苦苦做SEO,把关键词排名做到搜索引擎前几页,流量还比较稳定。但现在,越来越多人获取信息的入口变了。很多人遇到问题&#xff0c…

2026/10/11 12:46:35 阅读更多 →
大小核调度实操指南:三步强制绑定大核,让性能核不再闲置

大小核调度实操指南:三步强制绑定大核,让性能核不再闲置

用过混合架构处理器的朋友应该都有过这种体验:明明买的是高性能旗舰,结果打开某个老软件或大型游戏时,画面还是时不时卡一下,打开任务管理器一看,程序居然被系统安排在了一堆小核上,大核在旁边闲着。这不是…

2026/10/11 12:46:35 阅读更多 →
超翔TZ830-V3重装Win7驱动指南:硬件ID定位与三步安装法

超翔TZ830-V3重装Win7驱动指南:硬件ID定位与三步安装法

简介:这是清华同方超翔TZ830-V3国产化台式机在Win7 64位旗舰版下的驱动合集,适用于使用兆芯KX-U6780A处理器、THTF主板及Radeon R5 430显卡的用户,解决重装系统后网卡、声卡、显卡等硬件驱动缺失问题。压缩包共256个文件,包含dll动…

2026/10/11 12:46:35 阅读更多 →
python深入讲解魔术方法

python深入讲解魔术方法

前言 魔术方法(magic methods)就是那些名字两头带双下划线、由 Python 语法隐式调用的特殊方法,比如 __init__、__repr__、__eq__。它们不是给你手动调的接口,而是给语言本身看的钩子:你写了 __len__,len(o…

2026/10/11 12:45:34 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →