入口分析
一、主入口分析
package.json
"scripts": {
// ...
"build": "node scripts/build.js",
// ...
},
scripts/build.js
let builds = require('./config').getAllBuilds()
build(builds)
scripts/config.js
// Runtime+compiler ES modules build (for direct import in browser)
'web-full-esm-browser-prod': {
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.esm.browser.min.js'),
format: 'es',
transpile: false,
env: 'production',
alias: { he: './entity-decoder' },
banner
}
src/platforms/web/entry-runtime-with-compiler.js
// ...
import Vue from './runtime/index'
import { compileToFunctions } from './compiler/index'
// ...
Vue.prototype.$mount = function () {
// ...
}
Vue.compile = compileToFunctions
export default Vue
src/platforms/web/runtime/index.js
import Vue from 'core/index'
// ...
export default Vue
src/core/index.js
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
// ...
initGlobalAPI(Vue)
// ...
export default Vue
src/core/instance/index.js
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
function Vue(options) {
if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
二、方法
initMixin
vue 在此方法中声明了_init 方法。这实际上就是我们使用 vue 时, new Vue(options),实例化 vue 时执行的方法。此方法核心流程如下:
1. 合并 options 配置,并挂载至 vm.$options 上
2. initLifecycle
初始化 vm.$parent, vm.$root, vm.$children, vm.$refs 等属性值
3. initEvents
初始化 vm._events={},初始化事件系统 实际上是父组件在模板中使用 v-on 或@注册的监听子组件内触发的事件
4. initRender
主要定义 2 个方法:
vm._c,此方法用于用户使用 template 模式 vm.$createElement,此方法用于用户手写 render 函数
这 2 个方法,最终都会调用 createElement 方法,createElement 方法将在虚拟 DOM 章节重点分析,这里我们只需知道,此方法返回虚拟 DOM
5. 调用 beforeCreate 钩子
6. initInjections
此方法,里面的 inject 和 provide 是成对出现的。作用是父组件提供数据,任意嵌套层级的子组件可以去接受。其中 provide 是数据提供方,inject 是数据接受方。
7. initState
初始化 state, props, methods, computed, watch 其中初始化 state, props, methods 时, vue 会遍历 data 中所有的 key,检测是否在 props,methods 重复定义 props 变量有多种写法,vue 会进行统一转化,转化成{ a: {type: "xx", default: 'xx'} } 将 data, props 都挂载到 vm._data, vm._props 上。设置访问数据代理,访问 this.xx,实际上访问的是 vm._data[xx], vm._props[xx] 给_data,_props 添加响应式监听
8. initProvide
同 initInjections
9. 调用 created 钩子
stateMixin
- 定义 Vue.prototype.$data, Vue.prototype.$props 为响应式。
- 获取 vm.$data实际上是获取vm._data, vm.$props 实际上是 vm._props
- 定义 Vue.prototype.$watch 方法,实际上是实例化 Watcher 类
eventsMixin
- 在 Vue 原型上,定义$on, $once, $off, $emit 事件方法,并返回 vm
lifecycleMixin
- 在 Vue.prototype 上定义 _update, $forceUpdate, $destroy 方法
renderMixin
- 在 Vue 原型上,定义$nextTick 方法
- 在 Vue 原型上,定义_render 方法,值得注意的是,该方法会调用 vm.$createElement 创建虚拟 DOM,如果返回值 vnode 不是虚拟 DOM 类型,将创建一个空的虚拟 DOM。 虚拟 DOM:VNode,实际上是一个类。
三、总结
- Vue 本质上,是一个构造函数。
- 初始化了:state, props, methods, computed, watch,$destory,$data,$props,$forceUpdate 等。
- 对_data,_props 使用 Object.defineProperty 添加响应式
- 设置访问数据代理,访问 this.xx,实际上访问的是 vm._data[xx], vm._props[xx]
- 添加 event 事件系统,实际上初始化的是父组件在模板中使用 v-on 或@注册的监听子组件内触发的事件
- 挂载 createElement,为后续 render 返回虚拟 DOM 做准备。
- 调用对应的组件生命周期钩子, beforeCreate, created