【Vue原理】Diff - 源码版 之 重新建实例到开始diff

写文章不容易,点个赞呗兄弟


专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧
研究基于 Vue版本 【2.5.17】

若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧node

【Vue原理】Diff - 源码版 之 重新建实例到开始diff 函数

Diff 的内容不少,咱们先来探索一下从 新建实例 到 开始Diff 的流程走一遍,本文很短学习

先对整个流程有个把握,再仔细去探索 Diff 的思想this

公众号

首先,当你新建实例的时候,好比这样spa

公众号

你调用一个 Vue 函数,因此来看下 Vue 函数prototype

function Vue() {    

    ... 已省略其余

    new Watcher(function() {

        vm._update(vm._render());
    })

    ... 已省略其余

}

函数中作了两件事code

一、为实例新建一个 watcherblog

二、为 watcher 绑定更新回调(就是 new Watcher 传入的 function )token

每一个实例都会有一个专属的 watcher,而绑定的回调,在页面更新时会调用ci

咱们如今来看下简化的 Watcher 的源码

funciton Watcher(expOrFn){    

    this.getter = expOrFn;    

    this.get();

}



Watcher.prototype.get = function () {    

    this.getter()

}

watcher 会保存更新回调,而且在新建 watcher 的时候就会马上调用一遍更新回调

如今咱们继续看 更新回调的内容

vm._update(vm._render());

若是你看到以前的文章应该知道这两个函数的做用

如今就来简单说一下

1vm._render

生成页面模板对应的 Vnode 树,好比

公众号

生成的 Vnode 树是( 其中num的值是111 )

{    

    tag: "div",    

    children:[{        

        tag: "span"

    },{        

        tag: undefined,        

        text: "111"

    }]
}

这一步是经过 compile 生成的,具体的话能够简单看下 Compile - 白话版

有兴趣的有耐心的也能够看源码版

公众号

2vm._update

比较 旧Vnode 树 和 vm._render 生成的新 Vnode 树 进行比较

比较完后,更新页面的DOM,从而完成更新

ok,咱们看下源码

Vue.prototype._update = function(vnode) {  



    var vm = this;    

    var prevEl = vm.$el;    

    var prevVnode = vm._vnode;

    vm._vnode = vnode;    



    // 不存在旧节点

    if (!prevVnode) {

        vm.$el = vm.__patch__(
            vm.$el, vnode,
            vm.$options._parentElm,
            vm.$options._refElm
        );
    }    

    else {

        vm.$el = vm.__patch__(

            prevVnode, vnode

        );

    }
};

解释其中几个点

1 vm._vnode

看过 VNode - 源码版 应该知道,这个属性保存的就是当前 Vnode 树

当页面开始更新,而生成了新的 Vnode 树以后

这个属性则会替换成新的Vnode

因此保存在这里,是为了方便拿到 旧 Vnode 树

2 vm.__patch__

是的,没有错,你在两处地方看到这个东西

这个东西就是 Diff 的主要内容,内有乾坤,内容不少,不会在这里说,毕竟今天只探索流程

可是要看看这个东西怎么来的

var patch = createPatchFunction();

Vue.prototype.__patch__ =  patch ;

嗯,是通过一个 createPatchFunciton 生成的

而后赋值到 Vue 的原型上,因此能够 vm.__patch__ 调用喽

咱们再来讲说 _update 函数中出现的那两处 patch

1 不存在旧节点

不须要进行比较,直接所有建立

vm.$el 保存的是 DOM 节点,若是不存在旧节点,那么 vm.$el 此时也是不存在的

而传入 vm.$el 为空的时候,patch 拿到这个值判断为空的时候,就直接建立DOM,不会去作其余操做了

2 存在旧节点

须要把旧节点和新节点比较,尽可能找到最小差别部分,而后进行更新,这部份内容就是 Diff 的重点了,须要花费很多精力的。会放在其余文章进行记录

公众号


最后

鉴于本人能力有限,不免会有疏漏错误的地方,请你们多多包涵,若是有任何描述不当的地方,欢迎后台联系本人,有重谢

公众号

相关文章
相关标签/搜索