第二十章 vue3的element挂载主流程实现

221 阅读2分钟

vue3的element挂载主流程实现

首先我们先来对App.js的render函数进行一个改造,让它拥有元素,属性,还有children,构造如下图:

image.png

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是否为对象,如果为对象就走处理组件,为其他就走处理元素流程

image.png

2 接着实现处理元素的processElement,基本和处理组件思路一致,在processElement中去调用挂载组件的方法mountElement

image.png

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

image.png

然后我们给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函数,如图红框中的代码

image.png