本文主要来分析 vue3
组件的初始化(基于runtime-core(核心运行时)包
),将从createApp
、mount
等常用 API
入手来分析组件的挂载、普通元素的挂载流程。
createApp
1、创建一个应用实例。使用方式如下:
import { createApp } from 'vue'
import App from './App.vue'
const rootContainer = document.querySelector("#app");
createApp(App).mount(rootContainer)
2、内部实现:
function createRenderer(options) {...function render(vnode, container) {patch(null, vnode, container)}function patch(n1, n2, container) { ...}...return {createApp: createAppAPI(render),}
}
function createAppAPI(render) {return function createApp(rootComponent) {const vnode = createVNode(rootComponent);return {mount(rootContainer) {render(vnode, rootContainer)}};};
}
function createVNode(type, props, children) {const vnode = {type,props,children,component: null,key: props && props.key,shapeFlag: typeof type === "string" ? ShapeFlags.ELEMENT : ShapeFlags.STATEFUL_COMPONENT,el: null,};if (typeof children === "string") {vnode.shapeFlag |= ShapeFlags.TEXT_CHILDREN;} else if (Array.isArray(children)) {vnode.shapeFlag |= ShapeFlags.ARRAY_CHILDREN;}return vnode;
}
export const enum ShapeFlags { // 基于位运算确保代码运行更高效ELEMENT = 1, // 00000001 1FUNCTIONAL_COMPONENT = 1 << 1, // 00000010 2STATEFUL_COMPONENT = 1 << 2, // 00000100 4TEXT_CHILDREN = 1 << 3, ARRAY_CHILDREN = 1 << 4,SLOTS_CHILDREN = 1 << 5,TELEPORT = 1 << 6,SUSPENSE = 1 << 7,COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,COMPONENT_KEPT_ALIVE = 1 << 9,COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
}
const renderer = createRenderer({ // 传入dom操作相关方法,mountElement 会有说明createElement,patchProp,insert,remove,setElementText,
})
export function createApp(...args) {return renderer.createApp(...args);
}
上述代码主要做了如下几件事:1、定义 createRenderer
函数(用来创建一个自定义渲染器,通过提供平台特定的节点创建以及更改 API,用户可以在非 DOM 环境中也享受到 Vue 核心运行时的特性)。内部定义 render
函数,createRenderer
执行完后返回一个对象。 对象键名为 createApp
,键值是通过执行 createAppAPI
函数的返回值。
2、createAppAPI
是一个高阶函数,接收 render
函数作为参数,执行会返回 createApp
函数。
3、createApp
接收根组件 rootComponent
作为参数,首先会把 rootComponent
通过 createVnode
转化成该组件对应的 Vnode
,然后返回 mount
函数用来挂载应用。
4、createVnode
会创建一个 Vnode
, 该 Vnode
上会有 type
、props
、children
、key
、el
(虚拟 DOM 到真实 DOM 的映射,diff 时会用到)、shapeFlag
(标识节点类型)等。注: shapeFlag 基于二进制位运算,代码运行更高效。
4、mount
接收 rootContainer
作为参数 (它可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串),执行 mount
时会执行上述传入的 render
函数, 并把组件 Vnode
和 rootContainer
作为参数传入。
5、执行 createRenderer
返回 renderer
对象,对外暴露 createApp
。外界调用 createApp
时该函数内部会调用 renderer.createApp
,调用 mount
时最终会调用 render
函数执行挂载流程。
render
function render(vnode, container) {...
}
先举一个例子,假设有以下一段代码:
App.vue