发布于2021-05-30 08:10 阅读(1024) 评论(0) 点赞(16) 收藏(5)
----- 元素节点: 元素节点更贴近于我们通常所看到的真实DOM节点,他有描述节点标签名词的tag属性,描述节点属性如class,attributes等的data属性,有描述包含的子节点信息的children属性等,由于元素节点所包含的情况相对而言比较复杂,源码中没有像前三种节点一样直接写死。
VNode的作用: 用js的计算性能来换取操作真实DOM所消耗的性能,
----- VNode在Vue的整个虚拟DOM过程起到了什么作用呢。 其实VNode的作用是相当大的,我们在视图渲染之前,把写好的template模板先编译成VNode并缓存下来,等到数据变化页面需要重新渲染的时候,我们把数据发生变化后的生成的VNode与前一次缓存下来的VNode进行对比,找出差异。然后有差异的VNode对应的真实的DOM节点就是需要重新渲染的节点,最后根据有差异的创建出来的DOM节点再插入到视图中,最终完成一次视图更新。就是再数据变化前后生成真实的DOM对应的虚拟DOM节点
为什么要有虚拟DOM:
----- 就是以JS的计算性能来换取操作真实DOM所消耗的性能,Vue是通过VNode类来实例化不同类型的虚拟DOM节点,并且学习了不同类型节点生成的属性的不同,所谓不同类型的节点其本质还是一样的,都属VNode类的实例,只是实例化的时候传入的参数不同罢了。
有了数据变化前后的VNode,我们才能进行后续的DOM-Diff找出差异,最终做到只更新有差异的视图,从而达到尽可能少的操作真实DOM的目的,以节省性能
----- 而找出更新有差异的DOM节点,已达到最少操作真实DOM更新视图的目的。而对比新旧两份VNode并找出差异的过程就是所谓的DOM-Diff过程,DOM-Diff算法是整个虚拟DOM的核心所在。
Patch
在Vue中,把DOM-Diff过程就叫做patch过程,patch意思为补丁,一个思想:所谓旧的VNode(odlNode)就是数据变化之前属于所对应的虚拟DOM节点,而新的NVode是数据变化之后将要渲染的视图所对应的虚拟DOM节点,所以我们要以生成的新的VNode为基准,对比旧的oldVNode,如果新的VNode上有的节点而旧的oldVNode没有,那么就在旧的oldVNode上加上去,如果新的VNode上没有的节点而旧的oldVNode上有,那么就在旧的oldVnode上去掉。如果新旧Vnode节点都有,则以新的VNode为准,更新旧的oldVNode,从而让新旧VNode相同。
整个patch:就是在创建节点:新的VNode有,旧的没有。就在旧的oldVNode中创建
删除节点:新的VNode中没有,而旧的oldVNode有,就从旧的oldVNode中删除
更新节点:新的旧的都有,就以新的VNode为准,更新旧的oldVNode
更新子节点
/*
对比两个子节点数组肯定是要通过循环,外层循环newChildren,内层循环oldCHildren数组,每循环外层
newChildren数组里的每一个子节点,就去内层oldChildren数组里找看有没有与之相同的子节点
*/
for (let i = 0; i < newChildred.length; i++) {
const newChild = newChildren[i]
for (let j = 0; j < oldChildren.length; j++) {
const oldChild = oldChildren[i]
if (newChild === oldChild) {
// ...
}
}
}
那么以上这个过程将会存在一下四种情况
更新的时候分为三个部分:
function patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly) {
// vnode 与 oldVnode 是否完全一样,如果是,退出程序
if (oldVnode === vnode) {
return
}
const elm = vnode.elm = oldVnode.elm
// vnode 与 oldVnode是否都是静态节点,如果是退出程序
if (isTrue(vnode.isStatic) && isTrue(vnode.isStatic) && vnode.key === oldVnode.key && (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))) {
return
}
const oldCh = oldVnode.children
const ch = vnode.children
// vnode 有 text属性,若没有
if (isUndef(vnode.text)) {
if (isDef(oldCh) && isDef(ch)) {
// 若都存在,判断子节点是否相同,不同则更新子节点
if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
}
// 若只有vnode的子节点的存在
else if (isDef(ch)) {
/**
* 判断oldVnode是否有文本
* 若没有,则把Vnode的子节点添加到真实DOM中
* 若有,则清空DOM中的文本,再把vnode的子节点添加到真实DOM中
* */
if (isDef(oldVnode.text)) nodeOps.setTextContext(elm, '')
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
}
// 如果只有oldnode的子节点存在
else if (isDef(oldCh)) {
// 清空DOM中的所有子节点
removeVnodes(elm, oldCh, 0, oldCh.length - 1)
}
// 若vnode和oldnode都没有子节点,但是oldnode中有文本
else if (isDef(oldVnode.text)) {
nodeOps.setTextContext(elm, '')
}
// 上面两个判断一句话概括就是,如果vnode中既没有text,也没有子节点,那么对应的oldnode中有什么清空什么
} else if (oldVnode.text !== vnode.text) {
nodeOps.setTextContext(elm, vnode.text)
}
}
上面的我们了解了Vue的patch也就是DOM-DIFF算法,并且知道了在patch过程之中基本会干三件事,分别是创建节点,删除节点和更新节点。 创建节点和删除节点比较简单,而更新节点因为要处理各种可能出现的情况逻辑就比较复杂一些。 更新过程中九点Vnode可能都包含子节点,对于子系欸但的对比更新会有额外的一些逻辑,那么本篇文章就来学习Vue中是如何对比子节点的
更新子节点
当新的Vnode与旧的oldVnode都是元素节点并且都包含子节点的时候,那么这连个节点VNode实例上的chidlren属性就是所包含的子节点数组,对比两个子节点的通过循环,外层循环newChildren数组,内层循环oldChildren数组,每循环外层newChildren数组里的一个子节点,,就去内层oldChiildren数组里找看有没有与之相同的子节点
. 创建子节点
创建子节点的位置应该是在所有未处理节点之前,而并非所有已处理节点之后。 因为如果把子节点插入到已处理后面,如果后续还要插入新节点,那么新增子节点就乱了
. 移动子节点
所有未处理结点之前就是我们要移动的目的的位置
优化更新子节点:
前面我们介绍了当新的VNode与旧的oldVNode都是元素节点并且都包含了子节点的时候,vue对子节点是先外层循环newChildren数组,再内层循环oldChildren数组,每循环外层newChildren数组里的一个子节点,就去内层oldChildren数组里找看有没有与之相同的子节点,最后根据不同的情况做出不同的操作。这种还存在可优化的地方,比如当包含子节点数量较多的时候,这样循环算法的时间复杂度就会变得很大,不利于性能提升。
方法:
在前面几篇文章中,介绍了Vue中的虚拟DOM以及虚拟DOM的patch(DOM-Diff)过程,而虚拟DOM存在的必要条件是的现有VNode,那么VNode又是从哪里来的。 把用户写的模板进行编译,就会产生VNode
模板编译:
什么是模板编译:把用户template标签里面的写的类似于原生HTML的内容进行编译,把原生HTML的内容找出来,再把非原生的HTML找出来,经过一系列的逻辑处理生成渲染函数,也就是render函数的这一段过程称之为模板编译过程。 render函数会将模板内容生成VNode
整体渲染流程,所谓渲染流程,就是把用户写的类似于原生HTML的模板经过一系列的过程最终反映到视图中称之为整个渲染流程,这个流程在上文中已经说到了。
抽象语法树AST:
具体流程:
模板解析阶段:将一堆模板字符串用正则表达式解析成抽象语法树AST
优化阶段:编译AST,找出其中的静态节点,并打上标记
代码生成阶段: 将AST转换成渲染函数
有了模板编译,才有了虚拟DOM,才有了后续的视图更新
原文链接:https://blog.csdn.net/weixin_43405946/article/details/117359621
作者:哦八戒八戒
链接:http://www.qianduanheidong.com/blog/article/115904/611e422d7f779e8a79c7/
来源:前端黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 前端黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-3
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!