简易流程图,对比文字描述加深印象!~
vue3初始化:createApp(...)创建app实例
初始化一个app对象,createAppContext创建上下文内容
// app上下文内容
const context = createAppContext()
const app = context.app ={
// 属性
_component,
_container, // 根容器 div#app
config, // 全局配置 即 context.config
_context: context // 上下文对象, 存储全局配置与后续注册的 mixins, components, directives, provide
// 方法
use, mixin, component, directive, mount, unmount, provide
// ...
}
// createApp方法
createApp(...args) -> ensureRenderer().createApp(...args)
//基于渲染配置`rendererOptions`创建renderer,把逻辑与流程分离,通过注入逻辑的方法提供了可自定义渲染器。
ensureRenderer() -> createRenderer(rendererOptions) -> baseCreateRenderer(rendererOptions) -> createAppAPI(render, hydrate) -> return createApp
// 组合渲染器配置项,`nodeOps`dom操作相关 `patchProp`props按类别(class\style等)处理
const rendererOptions = extend({ patchProp }, nodeOps)
执行mount方法进行挂载
执行重写的mount方法。先获取根节点div#app,清空其HTML内容(template 和 render选项都不存在,则作为模板)。
执行原始mount方法
基于rootComponent配置项(创建app时的配置参数)生成vnode(用于初次patch), 装载上下文vnode.appContext = context。下一步执行render方法, 完毕后并设置挂载状态。isMounted = true
执行patch方法
render方法中调用patch方法,根据vnode类型进行不同的处理。首次处理执行processComponent -> mountComponent,进行根组件初始化。
-
createComponentInstance首先创建组件instance对象
-
setupComponent(instance)然后初始化props与slots、调用call setup()并根据情况将setup()返回结果或template编译结果设置为render函数。最后处理vue2中的options(如果存在,beforeCreate -> (methods/data/computed/watch/provide/...) -> created依次进行兼容处理)
-
setupRenderEffect设置instance副作用函数update并执行,触发beforeMount生命周期钩子,然后执行render (STATEFUL_COMPONENT)函数生成subTree子树const subTree = (instance.subTree = renderComponentRoot(instance))。 对子树再次进行patch,此时组件根节点类型已经确定(div),进行首次创建。processElement -> mountElement -> -> hostCreateElement,如果是非文本节点,则进行mountChildren递归patch子节点。
结束patch插入节点
(dirs beforeMount)全部结束后hostInsert(dirs mount)插入容器中,触发mounted生命周期钩子。
Vue2初始化流程:new Vue(...)
_init调用初始化方法,对options选项进行检查等处理。
beforeCreate hooks
- 执行
initLifecycle,注入 root, refs等属性 - 执行
initEvents,初始化事件监听 - 执行
initRender,注册渲染函数$createElement,注入listeners等属性
created hooks
- 执行
initInjections, 尝试inject注入 - 执行
initState,初始化 props, methods, data中的信息 - 执行
initProvide,尝试provide获取
beforeMount hooks
执行$mount方法,当render函数不存在时,进行template编译compileToFunctions(template, ...)得到render。
调用mountComponent方法,再次判断render是否存在。
mounted hooks
定义updateComponent方法,并作为实例的watcher的更新函数。执行vm._render()得到vnode,然后执行_update方法,初始化操作prevVnode不存在,调用__patch__方法,根据vnode创建真实节点, 存在子组件则递归创建,最后插入到父节点中,然后移除原始节点。
总结:
vue2提供Vue构造函数,只能通过new Vue()的方式进行初始化。vue3提供createApp方法,通过工厂函数的方式进行初始化。抽离逻辑与流程,提供自定义渲染器。vue2初次挂载分为beforeCreate/created/beforeMount/mounted四个生命周期,vue3初次挂载只有beforeMount/mounted两个生命周期。vue3会在创建组件时去处理setup选项中的内容,并根据判断按setup -> render -> template的优先级去设置渲染函数,并兼容vue2的options。然后设置setupRenderEffect副作用函数,继续进行初始化。
接下来继续了解响应式原理~~~