vue源码深入分析,步骤分层次解读,vue初始化render篇(包含vue双向绑定原理和新旧节点对比)

大家好,在网上看到过很多vue源码的解析,大多是copy和摘抄的,少有自己的理解,所以下决心花时间整理一遍自己对vue源码的理解。我只是一个普普通通的码农,如果本文有写的不对之处,希望各路大神指正,谢谢!

vue版本:2.5.17

源代码相关链接:https://cdn.bootcdn.net/ajax/libs/vue/2.5.17/vue.js

首先,本人采取的是最简单的debugger调试方法,按照步骤与逻辑分层次解析vue源码,我认为这是最快、最简单、也是最有效的方法。本文使用的vue调试代码如下:

<div id="main">
  <h1>count: {{times}}</h1>
  <p @click="cons">{{text}}</p>
</div>
<script src="./vue2.5.17/dist/vue.js"></script>
<script>
  var timeId = null
  var vm = new Vue({
    el: '#main',
    data: function () {
      return {
        times: 1,
        text: "我的"
      };
    },
    created: function () {
      var me = this;
      timeId = setInterval(function () {
        me.times++;
      }, 1000);
    },
    methods: {
      cons() {
        console.log(6211)
        debugger
        this.text = "你的"
      }
    }
  });

这是一个非常简单的例子,但可以很好地帮助我们解读vue的整个运行流程。

render渲染篇

首先找到mount周期函数,查看options的值,其实就是我们使用new Vue创建的实例对象
在这里插入图片描述
在这里插入图片描述
下面是template的值,即即将渲染的模板(html字符串)
在这里插入图片描述
然后进入创建编译函数createCompileToFunctionFn
在这里插入图片描述
进入createCompiler里,得到ast的值,即一个id为main的标签,内部包含三个字节点,分别是h1标签,文本标签(换行符标签),p标签

下面是code属性的render在这里插入图片描述
进入mountComponent函数
在这里插入图片描述
主要是调用了callHook方法,实现beforeMount(加载前的)生命周期
在这里插入图片描述
进入callHook方法,调用pushTargetpopTarget方法,完成生命周期beforeMount(此时vm的_hasHookEvent未定义,不需要绑定事件)
在这里插入图片描述
下面是_hasHookEvent方法:
在这里插入图片描述
这里关键的一步是给当前实例vm,绑定更新的函数_update,然后生成watcher实例,实现vm和更新组件的监视,当数据改变时,即通过watcher来通知更新。
在这里插入图片描述
进入watcher函数
在这里插入图片描述
之后进入到get方法,去获取数据
在这里插入图片描述
pushTarget函数里通过Dep绑定刚才Watcher监视数据的变化,h1标签中的times数据变成了1,这时通过vm实例绑定的_update方法。
在这里插入图片描述
在这里插入图片描述
先调用_render方法,得到idmain的节点后,调用_update方法。
在这里插入图片描述
之后通过__patch__方法,
在这里插入图片描述
对新旧节点进行对比在这里插入图片描述
主要去研究这句代码:
createChildren(vnode, children, insertedVnodeQueue);
在这里插入图片描述
之后销毁旧的节点,进入
在这里插入图片描述
函数销毁在这里插入图片描述
之后原节点销毁了,被新节点取代。
在这里插入图片描述
经过一系列的判断,进入parseHTML
在这里插入图片描述
渲染的大致流程是使用indexOf寻找开头的div标签,即”<”,最后将全部标签渲染到页面上。

总结和扩展

在新老虚拟DOM对比时:
1.首先,对比节点本身,判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换。
2.如果为相同节点,进行patchVnode,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)
3.比较如果都有子节点,则进行updateChildren,判断如何对这些新老节点的子节点进行操作。
4.匹配时,找到相同的子节点,递归比较子节点。

在diff比较中,只对同层的子节点进行比较,放弃了跨级的节点比较,加快了性能;只有当新旧children都为多个子节点时,才需要用核心的diff算法进行同层级比较。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值