news 2026/4/15 6:48:32

SortableJS 实现 Element UI Table行拖拽排序功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SortableJS 实现 Element UI Table行拖拽排序功能

Element UI Table组件基本使用(官方文档)
Sortable.js 官方文档

实现步骤

1. 安装SortableJS

通过npm安装:

npminstallsortablejs --save

或使用国内CDN(推荐):

<scriptsrc="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script>

2. 基础拖拽功能实现

在Vue组件中,通过ref获取Table的body部分,初始化Sortable实例:

<template><el-tableref="dragTable":data="tableData"row-key="id"borderstyle="width:100%"><el-table-columntype="index"width="50"></el-table-column><el-table-columnprop="name"label="名称"></el-table-column><el-table-columnprop="order"label="排序"></el-table-column></el-table></template><script>importSortablefrom'sortablejs'exportdefault{data(){return{tableData:[{id:1,name:'项目A',order:1},{id:2,name:'项目B',order:2},{id:3,name:'项目C',order:3}],sortable:null}},mounted(){this.initSortable()},beforeDestroy(){if(this.sortable){this.sortable.destroy()}},methods:{initSortable(){// 获取Table的tbody元素consttbody=this.$refs.dragTable.$el.querySelector('.el-table__body-wrapper tbody')this.sortable=newSortable(tbody,{// 拖拽时的动画效果animation:150,// 拖拽结束后的回调onEnd:(evt)=>{// 原索引constoldIndex=evt.oldIndex// 新索引constnewIndex=evt.newIndex// 处理数据排序this.handleDataSort(oldIndex,newIndex)}})},handleDataSort(oldIndex,newIndex){// 复制原数组constnewArray=[...this.tableData]// 删除原位置元素并插入新位置const[removed]=newArray.splice(oldIndex,1)newArray.splice(newIndex,0,removed)// 更新排序号newArray.forEach((item,index)=>{item.order=index+1})// 更新数据this.tableData=newArray// 这里可以添加保存到后端的API调用// this.saveSortOrder(newArray)}}}</script>

3. 实现原理详解

拖拽排序功能的实现主要分为三个核心步骤:

3.1 初始化Sortable实例

Vuemounted生命周期钩子中,通过Table组件的ref获取到表格的DOM元素,并找到包含行数据的tbody元素。SortableJS通过监听这个tbody元素来实现拖拽功能。

关键代码位于packages/table/src/table.vue的渲染结构中,表格主体使用了.el-table__body-wrapper类包裹,其中的tbody就是我们需要监听的目标元素。

3.2 拖拽事件处理

SortableJS提供了丰富的事件回调,我们主要使用onEnd事件在拖拽结束后触发数据更新。拖拽过程中,SortableJS会自动处理DOM元素的位置变化,我们只需要关注数据层面的调整。

3.3 数据排序与同步

当拖拽结束后,通过oldIndexnewIndex确定数据移动的方向和距离,然后调整数据数组中元素的顺序,并更新排序号。最后可以选择将新的排序结果同步到后端数据库。

4. 高级功能扩展

4.1 禁用特定行拖拽

有时我们需要禁止某些行的拖拽功能,可以通过Sortablefilter配置实现:

initSortable(){consttbody=this.$refs.dragTable.$el.querySelector('.el-table__body-wrapper tbody')this.sortable=newSortable(tbody,{animation:150,// 过滤不可拖拽的行filter:'.no-drag',// 拖拽结束后的回调onEnd:(evt)=>{this.handleDataSort(evt.oldIndex,evt.newIndex)}})}

然后在Table组件中为特定行添加no-drag类:

<el-tableref="dragTable":data="tableData"row-key="id":row-class-name="rowClassName"borderstyle="width:100%"><!-- 列定义 --></el-table>
methods:{rowClassName({row}){// 对id为2的行禁用拖拽returnrow.id===2?'no-drag':''}}

4.2 拖拽时样式自定义

通过CSS可以自定义拖拽过程中的样式:

/* 拖拽过程中的行样式 */.el-table__body tr.sortable-ghost{opacity:0.8;background-color:#f5f5f5;}/* 拖拽时的占位符样式 */.el-table__body tr.sortable-placeholder{background-color:#e9f7ef;border:1px dashed #409eff;}/* 禁止拖拽的行样式 */.el-table__body tr.no-drag{opacity:0.6;cursor:not-allowed;}

4.3 结合后端实现持久化

在实际应用中,我们需要将排序结果保存到后端,实现数据持久化:

methods:{asynchandleDataSort(oldIndex,newIndex){// 处理数据排序(同上)// ...// 保存到后端try{awaitthis.$api.saveSortOrder(newArray.map(item=>({id:item.id,order:item.order})))this.$message.success('排序已保存')}catch(error){this.$message.error('保存失败,请重试')// 保存失败时恢复原排序this.tableData=[...this.originalData]}}}

5. 性能优化建议

对于数据量较大的表格,建议添加以下优化措施:

  1. 虚拟滚动:结合Element UI的InfiniteScroll(packages/infinite-scroll)实现虚拟滚动,只渲染可见区域的行。
  2. 节流处理:如果需要在拖拽过程中实时更新某些数据,可以对更新函数进行节流处理:
import{throttle}from'throttle-debounce'// 在methods中updateDuringDrag:throttle(100,function(row,position){// 实时更新逻辑})
  1. 禁用不必要的动画:对于数据量超过100行的表格,可以考虑关闭Sortable的animation选项以提高性能。

6. 常见问题解决方案

6.1 拖拽后表格行高度异常

这通常是由于Table组件的高度计算问题导致的,可以在数据更新后调用TabledoLayout方法重新计算布局:

this.$nextTick(()=>{this.$refs.dragTable.doLayout()})

相关代码位于packages/table/src/table.vue的doLayout方法:

doLayout(){if(this.shouldUpdateHeight){this.layout.updateElsHeight();}this.layout.updateColumnsWidth();}

6.2 固定列(fixed)拖拽问题

当表格使用了fixed列时,拖拽可能会出现视觉错位。解决方案是同时监听固定列和主表格的拖拽事件:

initSortable(){// 主表格tbodyconstmainTbody=this.$refs.dragTable.$el.querySelector('.el-table__body-wrapper tbody')// 左侧固定列tbodyconstfixedLeftTbody=this.$refs.dragTable.$el.querySelector('.el-table__fixed-body-wrapper tbody')// 右侧固定列tbodyconstfixedRightTbody=this.$refs.dragTable.$el.querySelector('.el-table__fixed-right-body-wrapper tbody')// 为三个tbody都初始化Sortable[mainTbody,fixedLeftTbody,fixedRightTbody].forEach(tbody=>{if(tbody){newSortable(tbody,{// 配置同上,但只在主表格上处理数据更新onEnd:(evt)=>{if(tbody===mainTbody){this.handleDataSort(evt.oldIndex,evt.newIndex)}}})}})}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/25 11:16:55

如何创建一个PR

第一阶段&#xff1a;本地准备 (在终端操作) 这几步是为了确保你的代码在本地是干净、准确地打包好的。 1. 确认身份 git branch 作用&#xff1a;查看当前所在的分支。 检查点&#xff1a;必须看到 * crj_develop&#xff08;你的名字分支&#xff09;是绿色的。 为什么&…

作者头像 李华
网站建设 2026/4/10 19:47:48

vue表格vxe-table 单元格拖拽复制填充功能,如何自定义某个列霍某个单元格禁止拖拽复制值,自定义扩展区域赋值方法

vue表格vxe-table 单元格拖拽复制填充功能&#xff0c;如何自定义某个列霍某个单元格禁止拖拽复制值&#xff0c;自定义扩展区域赋值方法。比如有很多列&#xff0c; 业务需要实现b列不能拖拽复制单元格值&#xff0c;c列允许拖拽复制单元格值。那么可以使用&#xff0c;自定义…

作者头像 李华
网站建设 2026/4/12 2:59:47

在腾讯 CloudStudio 上部署 Moltbot 接入钉钉完整教程

继《Moltbot 接入飞书》和《Moltbot 接入企业微信》后,本文将详细介绍如何将 Moltbot 接入钉钉,实现智能 AI 助手功能。钉钉官方已开源 Moltbot 连接器,让接入变得更加简单! 一、前期准备 1.1 所需资源清单 在开始部署之前,请确保准备好以下资源: ✅ 钉钉企业账号:需要企业管…

作者头像 李华
网站建设 2026/4/4 17:23:20

HCIP 第一次作业

二、实验需求&#xff1a;qqw三、实验步骤-----思路1、首先&#xff0c;创建vlan并将相应端口划分到vlan中&#xff0c;满足PC1和PC3在vlan2的要求。2、为处于同一网段的PC2、PC4、PC5、PC6配置IP地址范围&#xff08;通过DHCP自动获取&#xff09;&#xff0c;同时设置访问控制…

作者头像 李华
网站建设 2026/4/5 1:34:54

CANN 生态实战:利用 `ge-graph-engine` 构建高性能 AI 推理流水线

CANN 生态实战&#xff1a;利用 ge-graph-engine 构建高性能 AI 推理流水线 cann组织链接&#xff1a;https://atomgit.com/cann ops-nn仓库链接&#xff1a;https://atomgit.com/cann/ops-nn 在深度学习模型从训练走向部署的过程中&#xff0c;图优化与执行引擎扮演着至关重要…

作者头像 李华