new Vue之后发生了什么?数据改变后,又发生了什么?
function Vue(options){
var data = options.data();
observe(data); // 使用观察将数据变成响应式
Object.defineProperty(this, "a", {
get(){
return data.a //将属性挂载到实例
}
set(val){
this.a = val
}
})
// 将methods中的方法绑定到this
Object.entries(methods).forEach(([methodsName,fn])=>{
this[methodsName] = fn.bind(this)
})
// 7.
var updateComponent = () =>{
this._update(this._render)
}
new Watcher(updateComponent)
}
创建vue实例和创建组件的流程基本一致
-
首先做一些初始化操作,主要是设置一些私有属性到实例中
-
运行生命周期钩子函数
beforeCreate -
进入注入流程:处理computed、methods、data、provide、inject,最后使用代理模式将他们挂载到实例中
-
运行生命周期函数
created -
生成
render函数:如果有配置,直接使用配置的render,如果没有,使用运行时编译器,把模板编译为render -
运行生命周期beforeMount
-
创建一个
Watcher,传入一个函数updateComponent,该函数会运行render,把得到的VNode再传入_update函数执行在执行render函数的过程中,会收集所有依赖,将来依赖改变时会重新运行updateComponent函数
在执行_update函数的过程中,触发patch函数,由于目前没有旧树,因此直接为当前虚拟DOM树的每一个普通节点生成elm属性,即真实DOM
如果遇到创建一个组件的vnode,则会进入组件实例化流程,该流程和创建vue实例流程基本相同,最终会把创建好的组件实例挂载vnode的componentInstance属性中,以便复用
-
运行生命周期mounted
重渲染
-
数据变化后,所有依赖该数据的
Watcher均会重新运行,这里仅考虑updateComponent函数对应的Watcher, -
Watcher会被调度器放到nextTick中运行,也就是微队列中,这样为了避免多个依赖的数据同时改变后被多次执行 -
运行生命周期beforeUpdate
-
updateComponent函数重新执行在执行
render函数的过程中,会去掉之前的依赖,重新收集所有依赖,将来依赖变化时会重新运行updateComponent函数在执行
_update函数的过程中,触发patch函数新旧两棵树进行对比
普通
html节点的对比会导致真实节点被创建、删除、移动、更新组件节点的对比会导致组件被创建、删除、移动、更新
当新组件需要创建时,进入实例化流程
当旧组件需要删除时,会调用就组件的
$destroy方法删除组件,该方法会先触发生命周期beforeDestroy,然后递归调用子组件的$destroy方法,然后触发生命周期destroyed当组件属性更新时,相当于组件的
updateComponent函数被重新触发执行,进入重渲染流程,和本节点相同 -
运行生命周期updated