当前位置: 首页 > news >正文

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

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

实现步骤

1. 安装SortableJS

通过npm安装:

npm install sortablejs --save

或使用国内CDN(推荐):

<script src="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-column type="index" width="50"></el-table-column><el-table-column prop="name" label="名称"></el-table-column><el-table-column prop="order" label="排序"></el-table-column></el-table>
</template><script>
import Sortable from 'sortablejs'export default {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元素const tbody = this.$refs.dragTable.$el.querySelector('.el-table__body-wrapper tbody')this.sortable = new Sortable(tbody, {// 拖拽时的动画效果animation: 150,// 拖拽结束后的回调onEnd: (evt) => {// 原索引const oldIndex = evt.oldIndex// 新索引const newIndex = evt.newIndex// 处理数据排序this.handleDataSort(oldIndex, newIndex)}})},handleDataSort(oldIndex, newIndex) {// 复制原数组const newArray = [...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() {const tbody = this.$refs.dragTable.$el.querySelector('.el-table__body-wrapper tbody')this.sortable = new Sortable(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的行禁用拖拽return row.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: {async handleDataSort(oldIndex, newIndex) {// 处理数据排序(同上)// ...// 保存到后端try {await this.$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() {// 主表格tbodyconst mainTbody = this.$refs.dragTable.$el.querySelector('.el-table__body-wrapper tbody')// 左侧固定列tbodyconst fixedLeftTbody = this.$refs.dragTable.$el.querySelector('.el-table__fixed-body-wrapper tbody')// 右侧固定列tbodyconst fixedRightTbody = this.$refs.dragTable.$el.querySelector('.el-table__fixed-right-body-wrapper tbody')// 为三个tbody都初始化Sortable[mainTbody, fixedLeftTbody, fixedRightTbody].forEach(tbody => {if (tbody) {new Sortable(tbody, {// 配置同上,但只在主表格上处理数据更新onEnd: (evt) => {if (tbody === mainTbody) {this.handleDataSort(evt.oldIndex, evt.newIndex)}}})}})
}
http://www.jsqmd.com/news/350136/

相关文章:

  • 预知2026年液槽式冷热冲击试验箱实力厂商排名,这些细节要知道 - myqiye
  • 晋中市英语雅思培训辅导机构推荐;2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025
  • 晋中市英语雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025
  • 71.字符串解码
  • 2026年全国垃圾焚烧炉厂家权威榜单 全场景覆盖 智能化节能化实力呈现 - 深度智识库
  • 两个节点部署Kubernetes集群完整指南(个人测试环境)
  • 盘点无锡可靠的不锈钢抛光厂,金属内腔抛光厂推荐有哪些 - 工业设备
  • 一文速通 OceanBase 物化视图能力
  • 分析青岛有名的龙膜授权企业,靠谱的推荐有哪些 - 工业品牌热点
  • 30.Android系统源码-libYUV实战 - YUV格式转换与SIMD优化核心技术
  • 变形监测必看!2026年单北斗GNSS变形监测系统排行榜,助力精准监测与安全管理
  • 导师又让重写?10个AI论文网站测评:本科生毕业论文写作神器推荐
  • 导师又让重写?8个AI论文网站深度测评,自考毕业论文写作必备!
  • 损耗直降 40%+:RFID 资产管理系统,企业降本增效的新解法
  • 靠谱的广告策划公司有哪些,推荐广告策划品牌企业 - 工业推荐榜
  • Java方法回顾及加深
  • 流延机费用怎么算,流延机制造厂哪家更值得选? - 工业品网
  • python接口自动化-全局常量如何在yaml文件中作为入参使用
  • 别再瞎找了!8个降AIGC平台测评:专科生降AI率必备神器
  • 2026更新版!10个AI论文工具测评:本科生毕业论文写作与科研写作必备指南
  • 多波束前视声呐采购攻略:高稳定性品牌与现货供应商优选 - 品牌推荐大师1
  • 2026年食品级软管厂家权威推荐:食品级PU/钢丝/透明软管源头厂家精选 - 品牌推荐官
  • afa
  • PC-自定义windows文件图标与默认打开方式
  • 【开源项目分享】跨平台+批量终端管理!自研视频编解码算法的国产远程桌面控制神器:JWRC发布1.8.2版本,用2ms延迟重新定义效率
  • 实用指南:基于java的SpringBoot/SSM+Vue+uniapp的出行服务系统的详细设计和实现(源码+lw+部署文档+讲解等)
  • 2026年氨水厂家权威推荐:电子级/食品级/化工用/脱硫氨水源头厂家精选 - 品牌推荐官
  • 2026天津短视频运营公司权威推荐,智能营销中台与精准获客实力解读 - 品牌鉴赏师
  • 【科技补全76】新概念英语点读工具NCE-Flow、在线材料管理器copyparty 部署指北
  • 2026航空插头厂家推荐,连接器兼容性与抗干扰能力深度测评 - 品牌鉴赏师