Vue源码解析之new Vue()时发生了什么

136 阅读2分钟

下面这段代码大家应该非常熟悉,它创建了一个Vue实例并挂载到了#app元素上。那么这个过程究竟发生了什么呢?本文将通过剖析源码的方式来一探究竟。 vue源码的github地址:github.com/vuejs/vue

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})
1.执行初始化过程

首先,找到 package.json文件,里面有这样一行代码

image.png

这里scripts/config.js就是指令执行的配置文件。 进入config.js,找到

image.png

可以看到项目的入口是 web/entry-runtime-with-compiler.js,这里web在src/platforms中,进入此文件,这里是实现$mount方法的

image.png

这里,返回了一个mountComponent方法,此方法执行组件的挂载。我们下一章节再说。

在这个文件上方,有一个引入Vue的语句:

image.png

于是,我们进入core/index.js,里面有

import Vue from './instance/index'

我们进入此文件

image.png

可以看到这里声明了Vue的构造函数,并在创建实例时会执行_this.init()方法。另外,此文件还执行了多个混入方法。我们着重看下initMixin方法,看下它做了哪些事。

进入 core/instance/init.js

image.png

可以看到它先进行了合并选项,把用户的选项与当前选项合并。 然后,

image.png

这里实现里$parent,$root,实现了自定义事件监听等。 最后,

image.png

如果设置了el选项,则挂载此组件。 上面几个初始化方法里,我们看下initState方法。进入 state.js的initData方法,看下数据初始化的过程。

image.png

image.png

这里的observe方法实现对data的遍历,进入observer/index.js

image.png

这里创建了一个Observer实例。

image.png

Observer构造函数里分别对数组和对象这两种数据类型做了处理。 先看对象类型:

image.png

walk方法对对象的每个属性做了响应式处理。

image.png

这里,使用Object.defineProperty对数据进行劫持,当用户改变属性的值的时候,使用dep.notify()通知更新。

2.组件挂载

回到上一章节的mountComponent方法,进入core/instance/lifecycle.js

image.png

这里有_render和_update方法,_render的作用是将组件渲染成虚拟dom节点,而_update方法的作用是将虚拟dom转化成真实dom显示在页面上。这里_render方法的实现,在renderMixin方法里core/instance/render.js里。它其实是通过createElement()函数将用户传进来的render方法转换成虚拟dom。

至于Vue是如何将比较虚拟dom节点进行更新的,我将在vue的diff算法中进行讲解。