Vue3 源码阅读
createApp
函数
代码所在位置:packages/runtime-dom/src/index.ts
源码
点击查看源码
export const createApp = ((...args) => {
const app = ensureRenderer().createApp(...args)
if (__DEV__) {
injectNativeTagCheck(app)
injectCompilerOptionsCheck(app)
}
const { mount } = app
app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
const container = normalizeContainer(containerOrSelector)
if (!container) return
const component = app._component
if (!isFunction(component) && !component.render && !component.template) {
// __UNSAFE__
// Reason: potential execution of JS expressions in in-DOM template.
// The user must make sure the in-DOM template is trusted. If it's
// rendered by the server, the template should not contain any user data.
component.template = container.innerHTML
// 2.x compat check
if (__COMPAT__ && __DEV__) {
for (let i = 0; i < container.attributes.length; i++) {
const attr = container.attributes[i]
if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
compatUtils.warnDeprecation(
DeprecationTypes.GLOBAL_MOUNT_CONTAINER,
null,
)
break
}
}
}
}
// clear content before mounting
container.innerHTML = ''
const proxy = mount(container, false, resolveRootNamespace(container))
if (container instanceof Element) {
container.removeAttribute('v-cloak')
container.setAttribute('data-v-app', '')
}
return proxy
}
return app
}) as CreateAppFunction<Element>
解析
createApp
函数是 Vue3 中的一个核心函数,用于创建一个 Vue 应用。createApp
函数接受一个参数,这个参数是一个组件对象。createApp
函数的实现非常简单,只是创建一个应用对象,并且返回这个应用对象。
代码可以看到通过调用 ensureRenderer().createApp
创建一个应用对象,然后重写了 mount
方法,最后返回了 app
实例。
ensureRenderer
如下
function ensureRenderer() {
return (
renderer ||
(renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
)
}
从代码中可以看到 ensureRenderer
函数中 render
是一个全局变量,如果 render
存在则直接返回,否则调用 createRenderer
函数创建一个渲染器。
这种写法很巧妙,通过全局变量 render
来缓存渲染器,避免重复创建渲染器,同时也能够确保核心渲染器逻辑可以在用户只从 Vue 导入响应性工具时进行树摇优化,从而减少打包体积。
export function createRenderer<
HostNode = RendererNode,
HostElement = RendererElement,
>(options: RendererOptions<HostNode, HostElement>) {
return baseCreateRenderer<HostNode, HostElement>(options)
}
深入查看 createRenderer
函数,可以发现 createRenderer
返回了 baseCreateRenderer
函数,这个函数是真正创建渲染器的函数。
h
函数
代码所在位置:packages/runtime-core/src/h.ts
源码
点击查看源码
export function h(type: any, propsOrChildren?: any, children?: any): VNode {
const l = arguments.length
if (l === 2) {
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
// single vnode without props
if (isVNode(propsOrChildren)) {
return createVNode(type, null, [propsOrChildren])
}
// props without children
return createVNode(type, propsOrChildren)
} else {
// omit props
return createVNode(type, null, propsOrChildren)
}
} else {
if (l > 3) {
children = Array.prototype.slice.call(arguments, 2)
} else if (l === 3 && isVNode(children)) {
children = [children]
}
return createVNode(type, propsOrChildren, children)
}
}
使用
// 创建一个 div 节点
const vnode = h('div')
// 创建一个带有属性的 div 节点
const vnode = h('div', { id: 'app' })
// 创建一个带有子节点和属性的 div 节点
const vnode = h('div', { id: 'app' }, ['foo'])
解析
h
函数是 Vue3 中的一个核心函数,用于创建虚拟节点。h
函数接受三个参数,第一个参数是节点的类型,第二个参数是节点的属性或者子节点,第三个参数是子节点。h
函数的实现非常简单,只是根据参数的不同,创建不同的虚拟节点。
总的来说,h
函数的作用就是创建虚拟节点,虚拟节点是一个轻量级的对象,用于描述真实 DOM 节点的结构。虚拟节点的好处是可以在不操作真实 DOM 的情况下,对 DOM 进行操作,这样可以提高性能。