Vue3 源码 | 如何挂载组件元素?
上一小节文章,讲述了 createApp
创建应用实例主流程逻辑,这篇就跟着上章文章继续看看虚拟节点的创建、渲染以及挂载。注意,这篇主要讲述新组件挂载流程,关于组件更新相关内容下篇再继续。
附上应用上下文执行 mount 的源码:PS:文章目录顺序及执行流程。
如果你对上一篇内容不熟悉,建议先熟悉下流程,内容文章如下:
createVNode
这个方法是根据组件和组件属性,生成一个 VNode 虚拟节点。
虚拟节点是什么,有什么好处呢?
VNode 的本质是一个描述 DOM 的 JavaScript 对象,是对抽象事物的描述。
跨平台
为数据驱动视图提供了媒介
对于频繁通过 JavaScript 操作 DOM 的场景,VNode 性能更优,因为它会等收集到足够的改变时,再将这些变化一次性应用到真实的 DOM 上。
下面看下生成 VNode 的源码:
从代码解析我们可以看出,createVNode 做了如下几件事:
对属性 props 标准化
将 VNode 类型信息进行编码为位图
创建 VNode 对象
对子节点进行标准化
render
存在 VNode 了,下面看看如果进行渲染。
render 函数很简单,根据传参决定是否销毁、还是创建或者更新组件。下面看看创建具体流程。
patch
包含了组件创建、和更新的相关实现,我们这里先看看创建相关逻辑。
从源码可以看出,当新旧虚拟节点不同,会先卸载旧节点。且 vNode 存在八种不同的类型,在 patch 函数中,会根据 vNode 的类型去做对应的处理,挂载 DOM,或者更新 DOM。
下面我们看下具备代表性的如何处理组件和 DOM 元素。
processElement
看看如何挂载 DOM 元素的。
本文只看挂载元素的过程,下面看看 mountElement
方法,因为函数代码多,下面删减下,只关注主流程。
整个过程我们可以缕清如下:
创建 DOM 元素,如果
vNode.el
非空且为静态虚拟节点,则直接克隆一个。先挂载元素子节点,因为当前节点可能依赖子节点的属性。如果子节点是文本节点,则直接设置节点内容;如果节点是数组,则遍历子节点,递归执行 patch 操作。相关代码,可自行查看。
属性存在,则处理元素的相关属性。
挂载元素到容器
container
上。
processComponent
这里直接看组件挂载的逻辑。
可以看出该函数,执行了一下步骤:
创建组件实例
设置组件实例
执行带副作用的渲染函数
下面看看,如果带副作用的渲染函数是如何执行的。
从源码可以处理如下:
effect 创建了一个副作用渲染函数
componentEffect
,当组件数据变化时,该函数会重新执行一次。渲染组件生成子树
subTree
,并把子树挂载到将子树的根节点保存到当前节点
整个组件挂载过程,执行了一些钩子函数,如
beforeMount、Mount
,以及keep-alive
的处理。
总结
至此便阅读了组件挂载过程。首先会创建虚拟节点 VNode,然后执行渲染逻辑。若创建的 VNode 为 null,则组件执行卸载过程,否则执行创建或者更新流程。本篇文章讲解挂载过程,创建的 VNode 存在 8 种类型,
我们针对组件和元素进行了分析。挂载元素的流程是:创建 DOM 元素->更新元素属性->递归挂载子节点,这里 DOM 相关操作,可以参考 nodeOps.ts
文件,底子里也是通过 dom api 来完成。挂载组件的过程是,创建组件实例->设置组件实例->执行带副作用的渲染函数,渲染组件子树,关于组件渲染更细则实现可以阅读 componentRenderUtils.ts
文件。
相关代码如下:
packages/runtime-dom/src/index.ts
packages/runtime-core/src/vnode.ts // 虚拟节点
packages/runtime-core/src/renderer.ts // 渲染器
packages/runtime-core/src/componentRenderUtils.ts // 组件渲染方法
packages/runtime-dom/src/nodeOps.ts // 描述节点的操作
版权声明: 本文为 InfoQ 作者【梁龙先森】的原创文章。
原文链接:【http://xie.infoq.cn/article/d15e39550a856776640f06dbe】。文章转载请联系作者。
评论