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的属性会发生改变,这样就省去了渲染器再去寻找变更点,从而提升性能。
浙公网安备 33010602011771号