场景

在一个列表展示页面上,使用了表格组件,原有组件本身不支持拖拽功能,需求要求在列表的基础上支持行拖拽排序。因此引入了Sortablejs插件。

问题及解决方案

引入Sortablejs后刚开始都很顺利,效果的拖拽基本功能效果已实现。代码如下

const tbody = this.$refs.Scheduling.querySelectorAll('.ant-table-tbody') // 元素选择器名称根据实际内容替换
Sortable.create(tbody[0]) //具体Sortablejs的api文档可查看官网

下一步就是保存数据

但是在保存数据的时候才发现,数据并没有修改,还是原来的数据,接下来就来处理数据排序的问题,经查看Sortablejs文档引入了onEnd方法,也可用onUpdate方法

代码修改如下

  const tbody = this.$refs.Scheduling.querySelectorAll('.ant-table-tbody') // 元素选择器名称根据实际内容替换
const _this = this
Sortable.create(tbody[0], {
onEnd({ newIndex, oldIndex }) {
const currRow = _this.databases.splice(oldIndex, 1)[0]
_this.databases.splice(newIndex, 0, currRow)
}
})

修改完之后本以为可以了,就去调试一下,就出现了比较诡异的问题。A和B拖拽交换位置之后,B和A又神奇的换回去了,整体都乱套了!很奇怪。

经查看资料才发现

Vue的实现原理,在Vue2.0之前是通过defineProperty依赖注入和跟踪的方式实现双向绑定。针对v-for数组指令,如果指定了唯一的Key,则会通过高效的Diff算法计算出数组内元素的差异,进行最少的移动或删除操作。而Vue2.0之后在引入了Virtual Dom之后,Children元素的Dom Diff算法和前者其实是相似的,唯一的区别就是,2.0之前Diff直接针对v-for指令的数组对象,2.0之后则针对Virtual Dom。DOM Diff算法在这里不再赘述,这里解释的比较清楚virtual-dom diff算法

假设我们的列表元素数组是[‘A','B','C','D']

渲染出来后的DOM节点是[$A,$B,$C,$D]

那么Virtual Dom对应的结构就是[{elm:$A,data:'A'},

{elm:$B,data:'B'},

{elm:$C,data:'C'},

{elm:$D,data:'D'}]

假设拖拽排序之后,真实的DOM变为[$B,$A,$C,$D]

此时我们只操作了真实DOM,改编了它的位置,而Virtual Dom的结构并没有改变,依然是[{elm:$A,data:'A'},

{elm:$B,data:'B'},

{elm:$C,data:'C'},

{elm:$D,data:'D'}]

此时我们把列表元素也按照真实DOM排序后变成[‘B','A','C','D']

这时候根据Diff算法,计算出的Patch为,VNode前两项是同类型的节点,所以直接更新,即把$A节点更新成$B,把$B节点更新成$A,真实DOM又变回了[$A,$B,$C,$D]

所以就出现了拖拽之后又被Patch算法更新了一次的问题,操作路径可以简单理解为

拖拽移动真实DOM -> 操作数据数组 -> Patch算法再更新真实DOM

根本原因

根本原因是Virtual DOM和真实DOM之间出现了不一致。

所以在Vue2.0以前,因为没有引入Virtual DOM,这个问题是不存在的。

在使用Vue框架的时候要尽量避免直接操作DOM

最后修改代码如下

 onEnd({ newIndex, oldIndex }) {
const currRowdom = tbody[0].children[newIndex]
const oldRowdom = tbody[0].children[oldIndex]
tbody[0].removeChild(currRowdom)
if (newIndex > oldIndex) {
tbody[0].insertBefore(currRowdom, oldRowdom)
} else {
tbody[0].insertBefore(currRowdom, oldRowdom.nextSibling)
} const currRow = _this.databases.splice(oldIndex, 1)[0]
_this.databases.splice(newIndex, 0, currRow)
}

Vue 结合Sortablejs实现table行排序的更多相关文章

  1. VUE +element el-table运用sortable 拖拽table排序,实现行排序,列排序

    Sortable.js是一款轻量级的拖放排序列表的js插件(虽然体积小,但是功能很强大) 项目需求是要求能对element中 的table进行拖拽行排序 这里用到了sorttable Sortable ...

  2. Vue. 之 Element获取table中选中的行

    Vue. 之 Element获取table中选中的行 问题描述: 如下截图,在Table中选择数据后,然后在点击“统计”按钮,获取Table表中选择的行 解决方案: 1. 给“统计”这个按钮添加一个点 ...

  3. JavaScript Table行定位效果

    作者:cloudgamer 时间: 2009-09-17 文档类型:原创 来自:蓝色理想 第 1 页 JavaScript Table行定位效果 [1] 第 2 页 JavaScript Table行 ...

  4. Javascript实现表格行排序

    网站开发中凡是用到表格来展示数据的,往往都要根据某个列来对行排序,下面是我从书上看到的一个行排序例子,看过后受益匪浅,故分享出来. 直接献上完整代码: <!doctype html> &l ...

  5. 循序渐进VUE+Element 前端应用开发(30)--- ABP后端和Vue+Element前端结合的分页排序处理

    在很多列表展示数据的场合中,大多数都会需要一个排序的处理,以方便快速查找排序所需的数据,本篇随笔介绍如何结合ABP后端和Vue+Element前端结合的分页排序处理过程. 1.Vue+Element前 ...

  6. asp.net实现动态添加table行

    asp.net动态的生成,删除table的行,主要是在后台动态创建单元行,单元表格,效果图: 2.代码: <%@ Page Language="C#" AutoEventWi ...

  7. jquery 获得table 行数

    1.获得Table总行数,分别使用了两种方法,结果不同:: 1).$("#table_Id").children("tr").length; 只能获得静态页面t ...

  8. table行转列

    table行转列 摘要 在使用ews调用exhange的收件箱的并在h5页面显示邮件详情的时候,因为返回的每封邮件的内容都是htmlbody,没有textbody.每封邮件又没什么规律,用正则表达式来 ...

  9. Datatable根据多行排序

    DataTable dt = new DataTable(); dt.Columns.Add("ID", typeof(int)); dt.Columns.Add("Na ...

  10. Lua table.sort排序

    在用table.sort 排序的时候注意,如果使用多个条件排序,应在一个排序函数里按照条件优先级进行比较排序. 例如 local t = { {time = , i = }, {time = , i ...

随机推荐

  1. 【Git】在 Eclipse 中使用 Git

    在 Eclipse 中使用 Git Eclipse 中默认自带了 Git 插件,通过点击 Help→About Eclipse IDE 可以查看 1 全局配置 1.1 配置用户名和邮箱 点击 Wind ...

  2. Oracle 归档模式

    sqlplus / as sysdba # 以下操作在`sqlplus`中执行 查看日志模式 SQL> archive log list; 数据库日志模式 非存档模式 自动存档 禁用 存档终点 ...

  3. PriorityQueue作用和源码

    一.PriorityQueue作用和源码 PriorityQueue跟前几个阻塞队列不一样,并没有实现BlockingQueue接口,只是实现了Queue接口,Queue接口中定义了几组放数据和取数据 ...

  4. rabbitmq学习与总结

    一.rabbitmq的使用场景 1.高并发的流量削峰 举个例子,假设某订单系统每秒最多能处理一万次订单,也就是最多承受的10000qps,这个处理能力应付正常时段的下单时绰绰有余,正常时段我们下单一秒 ...

  5. python,循环中通过判断条件中止循环的方法(braek 语句)

    直接对下方代码进行解析 for a in range(5): print(a) if a == 2: break 依次读取range内的数字,并答应出来.当读取出来的数字是2时,结束循环,执行后入下图 ...

  6. robotframework之数据驱动

    用robotframework做接口自动化时,如果执行用例条数比较多时,需要把用例存到表格当中,通过数据驱动读取表格内容. 一.引入第三方库 数据驱动的第三方库:DataDriver 直接在setti ...

  7. 🚀 放弃 Oh-My-Posh,转而手搓 FastPrompt,打造快速高效的命令提示

    「够用.够快.够自由」才是我心目中的终端提示符. 一个开发者的烦恼 每天打开 PowerShell,等待提示符加载完毕,我的内心就像在等待一个磨蹭的同事. 我用的是 Windows Terminal ...

  8. 使用 Podman Desktop 在 Windows 11 WSL2 环境中启动宿主机的 GPU 进行深度学习

    使用 Podman Desktop 在 Windows 11 WSL2 环境中启动宿主机的 GPU 进行深度学习 概述 本文将指导您如何利用 Podman Desktop 安装时提供的 WSL2 环境 ...

  9. 【经验】Ubuntu20.04虚拟机的网络问题|在NAT模式没有网络连接图标,桥接模式正常

    我的版本:Ubuntu20.04.04,iso是清华镜像站的release版本. 问题:NAT模式没有网络连接图标,或者图标闪一下就消失不见,并且无法获取IP地址:但是桥接模式的网络服务却是正常的. ...

  10. RPC实战与核心原理之健康检测

    健康检测:这个节点都挂了,为啥还要疯狂发请求 回顾 超大规模集群"服务发现"的挑战,服务发现的作用就是实时感知集群 IP 的变化,实现接口跟服务集群节点 IP 的映射.在超大规模集 ...