下面这段代码大家应该非常熟悉,它创建了一个Vue实例并挂载到了#app元素上。那么这个过程究竟发生了什么呢?本文将通过剖析源码的方式来一探究竟。 vue源码的github地址:github.com/vuejs/vue
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
1.执行初始化过程
首先,找到 package.json文件,里面有这样一行代码
这里scripts/config.js就是指令执行的配置文件。 进入config.js,找到
可以看到项目的入口是 web/entry-runtime-with-compiler.js,这里web在src/platforms中,进入此文件,这里是实现$mount方法的
这里,返回了一个mountComponent方法,此方法执行组件的挂载。我们下一章节再说。
在这个文件上方,有一个引入Vue的语句:
于是,我们进入core/index.js,里面有
import Vue from './instance/index'
我们进入此文件
可以看到这里声明了Vue的构造函数,并在创建实例时会执行_this.init()方法。另外,此文件还执行了多个混入方法。我们着重看下initMixin方法,看下它做了哪些事。
进入 core/instance/init.js
可以看到它先进行了合并选项,把用户的选项与当前选项合并。 然后,
这里实现里$parent,$root,实现了自定义事件监听等。 最后,
如果设置了el选项,则挂载此组件。 上面几个初始化方法里,我们看下initState方法。进入 state.js的initData方法,看下数据初始化的过程。
这里的observe方法实现对data的遍历,进入observer/index.js
这里创建了一个Observer实例。
Observer构造函数里分别对数组和对象这两种数据类型做了处理。 先看对象类型:
walk方法对对象的每个属性做了响应式处理。
这里,使用Object.defineProperty对数据进行劫持,当用户改变属性的值的时候,使用dep.notify()通知更新。
2.组件挂载
回到上一章节的mountComponent方法,进入core/instance/lifecycle.js
这里有_render和_update方法,_render的作用是将组件渲染成虚拟dom节点,而_update方法的作用是将虚拟dom转化成真实dom显示在页面上。这里_render方法的实现,在renderMixin方法里core/instance/render.js里。它其实是通过createElement()函数将用户传进来的render方法转换成虚拟dom。
至于Vue是如何将比较虚拟dom节点进行更新的,我将在vue的diff算法中进行讲解。