【vue3 原理】初始化元素流程

前言

初始化组件流程中的最后提到:

因为对根组件拆箱后只是得到了下一个层元素类型的vnode,没有实现对元素类型vnode的渲染逻辑

因此我们来实现这一部分

拆箱

runtime-core/renderer.js

diff 复制代码
function patch(vnode, container){
+	if(typeof vnode.type === 'string') {
+		processElement(vnode, container)
+	} else if(typeof vnode.type === 'object' && vnode.type !== null) {
		processComponent(vnode, container)	
+	}
}

元素类型的vnode的不需要挂载、初始化等一系列操作,和初始化组件流程不同需要走不同的逻辑

处理元素类型

runtime-core/renderer.js

js 复制代码
function processElement(vnode, container) {
	mountElement(vnode, container)
}

和[[初始化组件流程#处理组件|处理组件]]一样有两种情况:

  • 视图初始化
  • 视图更新

先关注初始化

初始化元素

runtime-core/renderer.js

js 复制代码
function mountElement(vnode, container) {
	const el = document.createElement('div')

	el.textContent = 'Hello, World'

	el.setAttribute('id', 'root')

	document.body.append(el)
}

这里虽然写死了渲染逻辑,但原理都是这个原理

创建元素

runtime-core/renderer.js

diff 复制代码
function mountElement(vnode, container) {
+	const el = document.createElement(vnode.type)

	el.textContent = 'Hello, World'

	el.setAttribute('id', 'root')

	document.body.append(el)
}

设置子节点

runtime-core/renderer.js

diff 复制代码
function mountElement(vnode, container) {
	const el = document.createElement(vnode.type)

+	const { children } = vnode
+	if (typeof children === 'string') {
+		el.textContent = children
+	} else if (Array.isArray(children)) {
+		 children.forEach(v => {
+			 patch(v, el)
+		 })
+	}

	el.setAttribute('id', 'root')

	document.body.append(el)
}
  • 子节点为字符串:直接覆盖
  • 子节点为数组:因此数组的成员必须由vnode组成,所以需要遍历递归[[初始化元素流程#拆箱|拆箱]],注意此时容器应该是当前元素

设置属性

runtime-core/renderer.js

diff 复制代码
function mountElement(vnode, container) {
	const el = document.createElement(vnode.type)

	const { children } = vnode
	if (typeof children === 'string') {
		el.textContent = children
	} else if (Array.isArray(children)) {
		 children.forEach(v => {
			 patch(v, el)
		 })
	}

+	const { props } = vnode
+	for(const key in props){
+		el.setAttribute(key, props[key])
+	}

	document.body.append(el)
}

props只能是对象,遍历设值即可

插入元素

runtime-core/renderer.js

diff 复制代码
function mountElement(vnode, container) {
	const el = document.createElement(vnode.type)

	const { children } = vnode
	if (typeof children === 'string') {
		el.textContent = children
	} else if (Array.isArray(children)) {
		 children.forEach(v => {
			 patch(v, el)
		 })
	}

	const { props } = vnode
	for(const key in props){
		el.setAttribute(key, props[key])
	}

+	container.append(el)
}

要注意插入到那个容器元素中

总结

初始化元素的流程和初始化组件流程的不同只是在拆箱时多了一条分支

到这里视图的初始化流程基本上没问题了,后续会慢慢补充一些细节

预告

前面的 demo 中我们打算在根组件render中使用this.msg获取setup状态,显然还没有实现这部分逻辑,看不到效果,只有undefinedthis是什么?它是怎么获取状态的?留到下一节解答

相关推荐
RaidenLiu3 分钟前
从 Provider 迈向 Riverpod 3:核心架构与迁移指南
前端·flutter
前端进阶者3 分钟前
electron-vite_18Less和Sass共用样式指定
前端
数字人直播6 分钟前
稳了!青否数字人分享3大精细化AI直播搭建方案!
前端·后端
江城开朗的豌豆8 分钟前
我在项目中这样处理useEffect依赖引用类型,同事直呼内行
前端·javascript·react.js
听风的码11 分钟前
Vue2封装Axios
开发语言·前端·javascript·vue.js
转转技术团队12 分钟前
前端安全防御策略
前端
掘金一周18 分钟前
被老板逼出来的“表格生成器”:一个前端的自救之路| 掘金一周 8.21
前端·人工智能·后端
cc_z24 分钟前
vue代码优化
前端·vue.js
龙在天27 分钟前
你只会console.log就Out了
前端
用户6817224572128 分钟前
h5实现点击电话进入拨打电话功能
前端