参考:Vue中使用Sortable
1 问题
Vue中使用Sortable拖拽表头达到改变列的位置的效果,
想法:使用该组件进行拖拽列,但它不会切换原表头下的数据,因此:1、先拖拽,2、手动交换原先vue中的表头,达到切换表下方的数据顺序。
现象:A和B拖拽交换位置之后,B和A又神奇得换回去了,但下面的数据确实已交换。
2 原因
2.1 原DOM映射关系
旧
表头虚拟DOM(vue) :[A,B]
表头真实DOM(html):[$A,$B]
2.2 操作
操作1,使用组件交换真实DOM:
[$B,$A]
操作2,代码中交换虚拟DOM:
[B,A]
[$B,$A]
2.3 操作解析
旧与操作2的”虚拟DOM“比较(sameVNode()):
旧:[ A, B]|| ||
新:[ B, A]
因为两个虚拟DOM相同,则直接替换,替换关系如下图所示,即以新的虚拟DOM顺序为最新顺序,然后用新的”真实DOM“替换旧的,即:
旧:[ $A, $B]^ ^| |
新:[ $B, $A]
找到替换关系后,准备替换,而此时旧的里面,两个真实DOM的顺序,已经交换为[$B,$A]
,那么替换关系则变成:
旧:[ $B, $A]^ ^\ /\//\/ \
新:[ $B, $A]
最终的结果则变成:
[B,A]
[$A,$B]
3 解决方案
3.1 使两个虚拟DOM不相同
只要key不同,那么两个虚拟DOM就不相同,不相同后会怎样,则参考下方4附录
<div key="1"/>
3.2 还原拖拽操作
参考最上方的参考文档。
4 附录
在虚拟DOM(Virtual DOM)的概念中,有一个函数通常被称为sameVNode,用于判断两个虚拟DOM节点是否相同。如果sameVNode返回false,这意味着两个虚拟DOM节点不相同,可能会触发重新生成真实DOM节点。
虚拟DOM是一种在内存中维护的、与真实DOM结构相似的JavaScript对象树。它充当了真实DOM的轻量级副本,可以进行高效的比较和更新。当进行界面更新时,首先会比较新旧虚拟DOM树的节点,而不是直接操作真实DOM。这种比较可以在内存中快速完成,减少了直接操作真实DOM所带来的性能开销。
如果sameVNode返回false,这意味着两个虚拟DOM节点的类型不同,或者某些关键属性不同,需要进行更新。在这种情况下,通常的做法是:
删除旧虚拟DOM节点对应的真实DOM节点。
创建新的真实DOM节点,基于新虚拟DOM节点的描述。
将新的真实DOM节点插入到正确的位置。
这个过程称为“协调”(reconciliation),它确保虚拟DOM树与真实DOM树保持同步。
需要注意的是,不是所有情况下都需要重新生成真实DOM节点。例如,如果两个虚拟DOM节点的内容没有发生变化,但是属性发生了变化,可能只需要更新真实DOM节点的属性,而不需要替换整个节点。
总之,sameVNode返回false是虚拟DOM更新的一个关键标志,意味着需要对相应的真实DOM节点进行更新操作,但具体的更新方式会根据不同的情况而变化。