Vue源码分析③ 虚拟DOM__Vue.js
发布于 3 年前 作者 banyungong 1071 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

Why虚拟DOM?

Vue在2.0版本引入虚拟DOM,这被认为是革命性的成果,因为虚拟DOM大大地提高了页面的渲染速度。

What虚拟DOM?

虚拟DOM是一个JavaScript对象,它是页面中真实DOM元素在JavaScript执行内存中的映射,由虚拟DOM来与数据状态(即在Vue中使用的数据变量)来进行绑定,而非真实DOM元素。

HOW虚拟DOM?

模板编译将Vue实例的模板进行解析编译并生成渲染函数,通过这个渲染函数我们可以构建出虚拟DOM。

有关模板编译生成渲染函数的可以看我的另一篇文章 : Vue源码分析② 模板编译

现在我们开始分析源码,看渲染函数是如何生成虚拟DOM的,还有虚拟DOM(下面统一称为VNode)是如何提高Vue应用的渲染速度的。

生成VNode

上面我们提到,VNode实际上就是通过执行渲染函数生成的,那么我们来看一看渲染函数的执行过程:

渲染函数的格式一般为:

with(obj){
    return _c('div',
              [
        		_c('h1',
                   {
                      style:({fontSize: title.size})
                   },
                   [
                      _v(_s(title.text))
                   ]),
                   _v(_s(content))
              ])
}

其中 _c 是最主要的方法,用于形成普通VNode,而_v则是生成一个文本VNode,_s则是解析出表达式的值。

_c主要就是调用VNode的构造函数,然后构造函数用我们渲染函数中的信息,如 tag(节点名)、attrs(节点属性)、children(子节点列表)等生成一个VNode实例。

我们可以看一下VNode的构造函数:

var VNode = function VNode (
    tag,
    data,
    children,
    text,
    elm,
    context,
    componentOptions,
    asyncFactory
  ) {
    this.tag = tag;
    this.data = data;
    this.children = children;
    this.text = text;
    this.elm = elm;
    this.ns = undefined;
    this.context = context;
    this.fnContext = undefined;
    this.fnOptions = undefined;
    this.fnScopeId = undefined;
    this.key = data && data.key;
    this.componentOptions = componentOptions;
    this.componentInstance = undefined;
    this.parent = undefined;
    this.raw = false;
    this.isStatic = false;
    this.isRootInsert = true;
    this.isComment = false;
    this.isCloned = false;
    this.isOnce = false;
    this.asyncFactory = asyncFactory;
    this.asyncMeta = undefined;
    this.isAsyncPlaceholder = false;
  };

其实就是将各项属性值给设置进去而已,没有任何的逻辑操作。

VNode的使用

当我们构建出VNode时,肯定要将它用来渲染到真实的页面上,下面我们来看一下执行过程:

首次渲染

当节点是首次渲染时,即在Vue应用启动后该节点是第一次使用,那么我们直接提供VNode创建出真实的DOM元素,并插入到页面中,这样我们便完成了VNode的渲染。

二次渲染

二次渲染指的是在我们渲染VNode时,之前已经渲染过VNode了,旧的VNode已经生成真实的DOM元素并存在于页面中了,那么我们应该对渲染出的新VNode和旧VNode进行对比(patch),找出两者的不同点,并根据不同点对页面中的某些DOM元素进行删除并插入新增的DOM元素,过程如下:

let component = new Vue({
	el: '#app',
	template: `
		<div>
            <h1>{{title}}</h1>
            <ul>
                <li v-for='(name,index) in list' :key= 'index'>
                    {{name}}
                </li>
            </ul>
         </div>
	`,
    data(){
        return{
            title: 'the title of Vue component',
            list: ['Jhon', 'Judy', 'Sandy']
        }
    }
})

component.title = 'the new title of Vue component'
component.list = ['Jhon', 'Jim', 'Judy']

我们将对上述过程进行流程图的分析:

1618119056245.png

看完上面的流程图,我们可能会疑惑,为什么在修改 ul 中的 li 节点,需要规定插入到哪个节点的前面,现在我们用思维导图来分析一下:

蓝色节点未已处理,橙色节点为未处理

1618128395871.png

版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者: runcode 原文链接:https://juejin.im/post/6949812233819914270

回到顶部