1.2 组件与模板的本质

1.组件的本质

定义:组件就是一组DOM元素的封装

复制代码
const MyComponet=function (){
    return  {
        tag:'div',
        props:{
            onClick:()=>alert('hello world')
        },
        children:'click me'
    }
}
复制代码

然后我们用虚拟DOM来描述组件:

const vcode={
    tag:MyComponet
}

为了能够渲染组件,需要渲染器的支持,修改前面的上节的render函数为:

复制代码
function renderer(vnode,container){
    if(typeof vnode.tag==='string'){
        mountElement(vnode,container)
    }else if(typeof vnode.tag==='function'){
        mountComponent(vnode,container)
    }
}

function mountElement(vnode,container){
    const el=document.createElement(vnode.tag);
    //遍历vnode.props,将属性事件添加到DOM元素
    for(const key in vnode.props){
        if(/^on/.test(key)){
            //如果key以on开头,说明它是事件
            el.addEventListener(
                key.substr(2).toLowerCase(),//事件的click方法
                vnode.props[key]//事件函数
            )
        }
    }
    if(typeof vnode.children==='string'){
        const text=document.createTextNode(vnode.children);
        el.appendChild(text)
    }else if(Array.isArray(vnode.children)){
        //递归地调用renderer函数
        vnode.children.forEach((child)=>render(child,el))
    }
    container.appendChild(el)
}

function mountComponent(vnode,container){
    //获取组件要渲染的虚拟DOM
    const subtree=vnode.tag();
    //递归地调用renderer函数
    renderer(subtree,container)
}
复制代码

当然这里的组件不止可以是函数,还可以是对象,只需要把条件判断中的'function'改为'object'即可。

2.模板的工作原理

对于编译器来说,模板就是普通的字符串,它会将该字符串生成一个功能与之相同的渲染函数:

模板:

<div @click="hanlder">
    click me
</div>

渲染函数:

render(){
    return h('div',{onclick:hanlder},'click me')
}

我们熟悉的.vue文件也是一样的道理:

复制代码
<template>
<div @click="hanlder"> 
    click me
</div>
</template>

<script>
export default {
    data(){/**/},
    methods:{
        hanlder:()=>{/**/}
    }
}
</script>
复制代码

渲染器会将模板渲染到<script>标签中所以最终在浏览器运行的代码是:

复制代码
export default {
    data(){/**/},
    methods:{
        hanlder:()=>{/**/}
    },
    render(){
        return h('div',{onclick:hanlder},'click me')
    }
}
复制代码

3.渲染器寻找变更点

形如:

复制代码
render(){
    return {
        tag:'div',
        props:{
            id:'foo',
            class:cls
        }
    }
}
复制代码

cls是一个变量,当cls变化时,渲染器需要寻找变更点,完全可以在render函数中添加一个属性:

复制代码
render(){
    return {
        tag:'div',
        props:{
            id:'foo',
            class:cls
        },
        pathchFlags:1//1代表class是动态的
    }
}    
复制代码

这里面添加了一个属性,代表class的属性会发生改变,这样就省去了渲染器再去寻找变更点,从而提升性能。

posted @ 2022-08-19 13:52  FRwind  阅读(49)  评论(0)    收藏  举报