问题
new Vue到底做了什么?
分析
在使用vue2的时候,需要构造一个Vue实例,以这个实例为根节点去实现数据的渲染;这个时候就出现了new Vue;
猜想
new Vue的时候将传递的options数据都绑定到vue实例上,并且挂载一些可以调用options的方法;
源码考证
version: v2.7.0
入口
调试vue源码,需要将代码clone下来,然后找到对应的入口:src\core\instance\index.ts
;这里只看到一个特别简单的Vue函数:
function Vue(options) {
if (__DEV__ && !(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue)
可以看出,当执行new Vue的时候就只执行了_init这个函数,那么_init从何而来的呢,很显然,能够通过this调用,那么必然是Vue原型上的方法,于是往上查找,通过initMixin这个突破口;
终于在src\core\instance\init.ts
找到initMixin这个方法:
Vue.prototype._init = function (options?: Record<string, any>) {
const vm: Component = this
// a uid
vm._uid = uid++
// ...
// merge options
// 合并选项,让实例拥有全局的配置项,例如:directive、components等等
if (options && options._isComponent) {
initInternalComponent(vm, options as any)
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor as any),
options || {},
vm
)
}
/* istanbul ignore else */
if (__DEV__) {
initProxy(vm)
} else {
vm._renderProxy = vm
}
// expose real self
vm._self = vm
// 初始化实例相关的属性,例如:$parent, $root, $children, $refs等等
initLifecycle(vm)
// 初始化自定义事件
initEvents(vm)
// 处理插槽和作用于插槽,提供_c和$createElement函数用于创建VNode,接收父组件传递$attrs和$listeners作为响应式数据
initRender(vm)
callHook(vm, 'beforeCreate', undefined, false /* setContext */)
// 处理祖辈传递的inject数据
initInjections(vm) // resolve injections before data/props
// 处理组件本身的状态:props、methods、data、computed、watch
initState(vm)
// 处理向下传递的provide数据
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
// ...
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
总结
在进行new Vue的时候,做了以下几件事情:
- 执行_init方法;
- 合并options配置项;
- initLifecycle初始化实例相关的属性:例如root、refs等等;
- initEvent初始化自定义事件;
- initRender设置DOM更新函数,处理插槽相关信息,将listeners处理为响应式数据;
- callHook(vm, 'beforeCreate')调用钩子函数;
- initInjections处理祖辈传递的inject数据;
- initState处理自身的状态:props、methods、data、computed、watch;
- initProvide处理向下传递的provide数据;
- callHook(vm, 'created')调用钩子函数;
- 判断是否options中明确了el属性,如果有那么执行挂载函数,进行数据渲染。