vue3的element挂载主流程实现
首先我们先来对App.js的render函数进行一个改造,让它拥有元素,属性,还有children,构造如下图:
App.js:
import {h} from '../../lib/guide-ljp-vue.esm.js'
export const App = {
// .vue
// <template></template> 最总转化成render函数
// render 由于还没有实现编译功能 所以先直接写render函数
render() {
// ui
return h('div',
{
id:'root',
class:['red','hard']
},
// +this.msg
[h('p',{class:'red'},'hi'),h('p',{class:'blue'},'mini-vue')]
)
},
setup(){
return{
msg:'mini-vue'
}
}
}
1 接着上篇文章中的报错,我们需要在patch中判断vnode中的type是否为对象,如果为对象就走处理组件,为其他就走处理元素流程
2 接着实现处理元素的processElement,基本和处理组件思路一致,在processElement中去调用挂载组件的方法mountElement
3 挂载元素我们就分为了4步
3.1 使用document.CreateElement创建el元素
3.2 对children属性的处理,如果为string就将children设置为元素的文本el.textContent=children,如果为数组就遍历children中的元素进行patch循环处理
3.3 对props属性的处理,循环props对象给当前元素也就是el增加属性值
3.4 处理完以上操作后就直接把el元素append到container
然后我们给index.html中的style增加样式属性,可以验证props中属性是否设置生效了,给body中加入id为app的div,作为其他元素的存放容器
render.ts代码如下
import { isObject } from "../shared/index"
import { createComponentInstance, setupComponent } from "./components"
export function render(vnode,container){
// patch
patch(vnode,container)
}
function patch(vnode,container){
// debugger
if(isObject(vnode.type)){
// 处理组件
processComponent(vnode,container)
} else {
processElement(vnode,container)
}
}
function processComponent(vnode,container){
mountComponent(vnode,container)
}
function processElement(vnode,container) {
mountElement(vnode,container)
}
function mountElement(vnode,container){
const el = document.createElement(vnode.type)
const {children,props} = vnode
// children
if(typeof children === 'string') {
el.textContent = children
} else if(Array.isArray(children)) {
mountChildren(children,el)
}
// props
for(const key in props){
const val = props[key]
el.setAttribute(key,val)
}
container.append(el)
}
function mountChildren(children,el) {
children.forEach(v => {
patch(v,el)
})
}
function mountComponent(vnode,container) {
const instance = createComponentInstance(vnode)
setupComponent(instance)
setupRenderEffect(instance,container)
}
function setupRenderEffect(instance,container) {
const subTree = instance.render()
patch(subTree,container)
}
index.html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.red{
color:red
}
.blue{
color:blue
}
</style>
<script src="main.js" type="module"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
最后还有一个可以优化的点就是,判断children的时候,如果children是Array的话,里面的操作其实就是一个挂载children的操作,所以我们可以把里面的逻辑抽出来作为mountChildren函数,如图红框中的代码