紧接上回分解,咱继续分析vue是如何进行渲染的!
创建DOM节点
有了vnode后,vue还需要根据vnode来创建DOM节点。如果是首次渲染,那么vue会走创建的逻辑。如果是数据的更新导致的重新渲染,那么vue会走更新的逻辑。
首次渲染
因为是首次渲染,所以不存在先前老的vnode,因此无需进行比较。vue直接调用 createElm 方法创建DOM元素。具体的创建步骤如下:
1.首先为vnode创建DOM元素。
2.如果vnode有子节点,逐个为其子节点创建DOM元素,并将子DOM元素插入到vnode的DOM元素上。
3.调用setAttribute 为vnode的DOM元素添加属性。
4.将vnode的DOM元素插入到其父元素上。
重新渲染
如果不是首次渲染,而是由数据变化所触发的重新渲染,那么vue会最大限度地复用已创建的DOM元素。而复用的前提就是通过比较新老vnode,找出需要更新的内容,然后最小限度地进行替换。这也是vue设计vnode的核心用途。
vue源码中可以看到(此处先忽略),当新老vnode完全相等的情况下,vue不会对该节点重新渲染,直接跳过了。
如果新vnode发生了变化,那么vue会遵循以下步骤更新DOM元素:
1.更新DOM元素的属性。
这个在首次渲染那部分提到了一些。vue内实现了若干个属性处理模块,专门用于DOM元素属性的创建和更新。这些模块中基本都实现了create、update这两个处理函数。create 负责DOM元素属性的创建,update 负责DOM元素属性的更新。cbs.update[i](oldVnode, vnode) 的意思就是逐个调用这些模块上的 update 方法,以更新发生改变的DOM元素属性。
2.更新DOM元素的子元素。关于DOM子元素的更新分为几种情况
如果新老vnode的子节点都是文本节点且文本内容不同,处理方式更新DOM元素的textContent属性值。
如果新老vnode的子节点都是非文本节点,需要调用 updateChildren 递归地去更新子节点。
如果新vnode的子节点是非文本节点,而老vnode的子节点是文本节点,需要清除DOM元素的文本,并创建子vnode的DOM元素插入到其父节点的DOM元素上。
如果新vnode的子节点不存在,但老vnode的子节点存在,那么调用 removeVnode 删除老vnode的子节点对应的DOM元素。
如果老vnode的子节点是文本节点,而新vnode的子节点不存在,则清空老DOM元素的文本。
大量的DOM操作会极损耗浏览器性能。vue在每次数据发生变化后,都会重新生成vnode节点。通过比较新老vnode节点,找出需要进行操作的最小DOM元素子集。根据变化点,进行DOM元素属性、DOM子节点的更新。这种设计方式大大减少了DOM操作的次数。
这次文章大部分都是看一些博客文章所了解的内容,基本上可以了解vue如何创建和如何渲染界面,还是老话好记性不如烂笔头 自己做了一些总结 可以加深理解!