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

2019-09-12 admin

写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 【2.5.17】

如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧

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

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

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

公众号

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

公众号

你调用一个 Vue 函数,所以来看下 Vue 函数

function Vue() {    

    ... 已省略其他

    new Watcher(function() {

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

    ... 已省略其他

}

函数中做了两件事

1、为实例新建一个 watcher

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

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

我们现在来看下简化的 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 的重点了,需要花费不少精力的。会放在其他文章进行记录

公众号


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

公众号

[转载]原文链接:https://segmentfault.com/a/1190000020367141

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-74923.html

文章标题:【Vue原理】Diff - 源码版 之 从新建实例到开始diff

相关文章
破解前端面试(80% 应聘者不及格系列):从 闭包说起
不起眼的开始 招聘前端工程师,尤其是中高级前端工程师,扎实的 JS 基础绝对是必要条件,基础不扎实的工程师在面对前端开发中的各种问题时大概率会束手无策。在考察候选人 JS 基础的时候,我经常会提供下面这段代码,然后让候选人分析它实际运行的结...
2017-06-02
NodeJS参考手册pdf版
下载地址:Nodejs参考手册PDF版下载 ...
2015-11-12
HTML5究竟会火到什么地步
这已经是第N次,HTML5火热了起来,这次的火热是否可以延续? H5的最大优势就是可以在网页上直接调试和修改,而且更重要的是,它几乎不用考虑用户的机型与适配性问题。智能手机主要被分裂为两大系统:Android和iOS,一个做应用的团队,怎么...
2015-11-12
javaScript+turn.js实现图书翻页效果实例代码
为了实现图书翻页的效果我们在网上可以看到很多教程 在这里推荐turn.js 网上的turn.js 有api 不过是英文的  很多人看起来不方便 .关于代码也是奇形怪状在这里我将详细讲解如何使用turn.js实现翻页效果 ,本篇文章只是讲解 ...
2017-03-16
jQuery中DOM树操作之使用反向插入方法实例分析
本文实例讲述了jQuery中DOM树操作之使用反向插入方法。分享给大家供大家参考。具体分析如下: 使用反向插入方法 这里我们先把创建的内容插人到元素前面,然后再把同一个元素插人到文档 中的另一个位置。通常,当在jQuery中操作元素时,利用...
2015-11-13
可以从CSS框架中借鉴到什么
现在很多人会使用 CSS 框架进行快速建站。   那 CSS 框架是什么呢,它通常是一些 CSS 文件的集合,这些文件包括基本布局、表单样式、网格、简单组件、以及样式重置。使用 CSS 框架大大降低工作成本进行快速建站。   当然对于一些大...
2016-03-11
JavaScript短路原理精简代码
js中||和&&的特性帮我们精简了代码的同时,也带来了代码可读性的降低,虽然高效,但请灵活使用。 在js逻辑运算中,0、""、null、false、undefined、NaN都会判为false,其他都为t...
2015-11-12
JavaScript游戏之连连看源码分享
JavaScript游戏之连连看源码 下载地址:JavaScript游戏之连连看源码 解压密码:www.javascriptcn.com ...
2015-11-12
vue.js实现请求数据的方法示例
vue2.0示例代码如下: var vm = new Vue({ el:"#list", data:{ gridData: "", }, ...
2017-03-20
三步搞定vue在vscode的环境配置问题
1. vscode基础开发插件 vscode-icons 图标美化 Debugger for Chrome 调试 Beautify 代码格式化 Prettier 代码格式化 ESLint 代码规范 JavaScript (ES6) cod...
2017-12-25
回到顶部