当前位置: 首页 > 科技观察

走进拖着绿油鸡的科普奥秘

时间:2023-03-18 17:51:42 科技观察

1.写在前面的小朋友,是不是问号很多?学过的知识过一段时间就会忘记,下次遇到还是需要百度。如果你遇到过这种情况,那我们就是同父异母的兄弟!!好兄弟,几经坎坷,终于找到好办法了!也就是一边修bug一边学习。正如彼得帕克的叔叔对他说的那样:能力越大,责任越大。我也有自己的座右铭,那就是:更多的错误,更多的力量。[手动滑稽]开玩笑的。但道理并不粗糙,当我们看到并修复了很多稀奇古怪的bug后,我们的知识就会融入到修复的过程中,记忆会很深刻。因为这一切的背后都是一夜的加班和辛苦!最近,我遇到了一个很奇怪的错误。一开始我一点头绪都没有,只能坐在办公桌前痛苦地挠着头。在后续解决这个bug的过程中,总结了之前学习的知识点,进步明显!!因此,我写了一篇文章分享给大家。2.什么是碧游记?先简单说下业务场景:管理后台一个列表页有多个数据,数据之间有顺序。现在每一条数据都需要能够拖拽排序。需求看似很简单,只涉及到一个排序界面,难点在于列表数据的拖拽。当我们每天遇到拖拽式需求开发的时候,当然要看看有没有合适的轮子可以使用。在之前的开发中,我使用vue-draggable在两个容器之间拖拽数据。但是这个列表数据拖拽没有那么复杂,有点大材小用了。这时,又一个轻量级的js插件映入了我的眼帘:SortableJS。1、SostableJS的使用SortableJS非常轻量级,官网的demo非常直观。但是它的配置项描述文档写的很烂,有些API描述找不到,导致排查问题非常困难。{{scope.row.surveyName||'--'}}

如上代码所示,SortableJS的使用非常简单,只需要在页面初始化的时候获取指定的dom节点,然后新建一个Sortable的实例即可,虽然视图级别的数据顺序发生了变化,但模型级别的数据顺序没有改变。所以我们需要在onEnd函数中手动更改列表数据顺序。2.遇到的神秘问题。上面的代码我已经写完了。本以为完了,可以安心测试了。可就在这时,一个神秘的虫子出现了。我在调试的时候出现了一个奇怪的现象:第一行和第三行的数据拖动交换后,对应的数据数组的顺序和视图完全不一致。这到底是什么?重新检查我们之前写的代码,我们的操作似乎没问题。SortableJS移动了真正的DOM之后,我们也在onEnd中更改了data中的列表数组顺序。列表数组数据渲染的顺序应该和真实DOM的顺序是一致的,但是为什么奇怪的不一致呢?3.问题分析任何错误修复都需要全面的问题分析。由于视图层的顺序改变了,模型层的数据没有正确改变。那么问题就出在模型层列表的数组数据的变化上!回头看上面写的代码,唯一对数组数据顺序的操作是在onEnd函数中。那么这里有什么问题吗?然而,生活并不是那么顺利。调试onEnd函数后,发现我做的操作是正确的。但是最终list数组的顺序和view层不一致!!太难了!!4.问题解决苦恼了一个下午,终于在谷歌的帮助下找到了答案。先说一下最终解决问题的方法:就是给el-table标签加一个key,用来区分每条数据的唯一性。难以置信,让我难受了一个下午The只需一行代码即可解决问题。3.神秘BUG探源完成BUG修复后,我静下心来梳理BUG的根源。这种诡异失控的情况让我很好奇,想弄清楚背后的原因。看了前辈们的博客,知道了这个问题的根本原因:VirtualDOM和realDOM不一致。1.VirtualDOM和RealDOM在Vue框架兴起之前,前端开发还是使用原生封装的JQuery框架。但其本质是对页面DOM节点的操作,顶多是操作起来比较方便。在这种背景下,前端开发的步骤绕不开获取dom节点的过程。Vue、React等框架流行之后,前端开发出现了一种新的开发模式:无需关注和操作dom节点。这时一个新的概念诞生了——VirtualDom。虚拟DOM是相对于真实DOM而言的。真正的DOM是页面的DOM模型,有大量的dom节点。在JQuery时代,我们的开发过程就是和这些真实的dom节点打交道的过程。让我们回顾一下Vue的实现原理。在Vue2.0之前,双向绑定是通过defineProperty依赖注入和跟踪来实现的。对于v-for命令,如果指定了唯一键,则会通过高效的Diff算法计算数组中元素之间的差异,进行最少的移动或删除操作。Vue2.0之后引入VirtualDom之后,子元素的DomDiff算法其实和前者差不多。唯一不同的是,2.0之前Diff直接以v-for指定的数组对象为目标,2.0之后则是以VirtualDom为目标。2、具体例子假设我们的列表元素数组为:lettableData=['A','B','C','D']渲染后的DOM节点为:lettableDate_dom=['$A','$B','$C','$D']那么VirtualDom对应的结构是:lettableData_vm=[{el:'$A',data:'A'},{el:'$B',data:'B'},{el:'$C',data:'C'},{el:'$D',data:'D'},]拖拽排序后真实DOM变为:['$B','$A','$C','$D']因为SortableJS只是操作了真实DOM,改变了它的位置,而VirtualDom的结构并没有改变,所以还是:lettableData_vm=[{el:'$A',data:'A'},{el:'$B',data:'B'},{el:'$C',data:'C'},{el:'$D',data:'D'},]在实例化Sortable实例时,我们在onEnd函数中更改了数组数据排序操作,将列表元素更改为与真实DOM排序一致:['B','A','C','D']列表元素发生变化后,此时会根据Diff算法重新渲染页面,导致bug。操作路径可以大致理解为:拖拽真实DOM->操作数据数组->Patch算法然后更新真实DOM3。进一步探索当我写到这里时,我感到无能为力。我以为我已经明白了这个bug的原因,但是当我在写文章的时候回顾了之前的开发细节,我发现知识网络仍然存在很多漏洞。为了进一步探索,有必要了解DOM-Diff算法的细节,才能真正理解为什么只有设置唯一键才能解决这种奇怪且难以排查的错误。在这一点上我还欠缺很多,希望在以后的工作中多问一个为什么。4、自省回顾整个bug修复过程,自己的编码和知识学习上存在几个问题,以后会整理和弥补。1、日常编码中编码标准松散的问题,可以说是一个职业生涯的始末。这个问题可大可小,但如果把整个时间线拉长到10年、20年,就足以对我们的职业生涯产生重大影响。以这道题为例,Vue官方文档说在使用v-for指令时,不建议直接使用数组数据的索引作为key属性的值。但是回头看我之前的编码,为了省事直接使用了索引。由于不涉及对真实DOM的更改,因此没有问题。而也正是这种没毛病,让我继续使用这种不推荐的写法,最终绊倒了这个拖拽需求。修正并形成严密的编码标准,不仅可以提前避免一些问题,还可以培养开发人员优秀的编程思维。随着时间的推移,遵循严格编码标准的开发人员会潜移默化地提高他们对编程的理解。2.Knowingwhynotknowingwhy知道为什么很容易做到。当我们遇到bug时,我们可以通过穷举和查询的方法找到解决问题的方法。但是如果你只是停留在这里,不进一步去探究问题的根源。我们总是编码工具人,呜呜呜!就像现在流行的前端框架Vue和React一样,包括我在内的大部分人更多的停留在框架的使用上。对框架的原理了解不多,遇到问题多半是临时抱佛脚。在这种情况下,我们的知识深度还不够。那么在遇到一些奇怪的bug时,我们的思维就局限于一个狭小的空间,无法透过现象看本质,定位到问题的根源。古语有云,贵重之物,得来不易。翻山越岭,那种成就感足以让我们开心很久。五、总结给大家喂了一波鸡汤之后,我还是想总结一下这篇文章。本文从笔者在工作中遇到的一个奇怪的拖拽bug开始,描述了业务场景,然后讲了具体的解决方案。然后探究bug的原因:虚拟DOM和真实DOM不一致。然后从日常开发过程中很少遇到的情况,用一个简单的demo来描述出现的原因。并进一步定位到问题的根源:Dom-diff算法。后面的diff算法我也没有深入描述,留给小伙伴们自己研究研究。更让笔者感叹的是,一个普通的bug背后,牵涉到方方面面、深奥的知识。那么反过来想想,当我们在学习这些知识的时候。如果只是零敲碎打的学习,没有融入系统的知识框架。那么我们的技术水平就永远无法提高。希望这篇文章能给你带来一些帮助。在以后的日子里,大家一起学习,一起进步!六、参考文章深入浅出解释Vue中的key值:https://juejin.cn/post/6844903865930743815Vue中使用SortableJS:https://www.jianshu.com/p/d92b9efe3e6avirtual-dom(Vue实现)简介分析:https://segmentfault.com/a/1190000010090659许浩星,微医前端技术部前端工程师。一个相信人生的乐趣一半在静一半在动的有志青年!