news 2026/5/13 0:09:26

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/5/11 14:13:53

这款 MEMS 陀螺升级了哪些地方?

普通的MEMS陀螺一般会在-40~85℃的工作温度下测量角速度。但是&#xff0c;随着MEMS陀螺精度水平越来越高&#xff0c;可以满足越来越多领域的需求。因此&#xff0c;MEMS陀螺在石油测井、定向钻井等领域都有很好的建树。想要完成钻井的工作&#xff0c;MEMS陀螺必须符合耐高温…

作者头像 李华