使用js对象来描述UI更加的灵活。“这种对象”在vue框架中被称为虚拟DOM,渲染函数内部可以创建虚拟DOM,然后vue.js可以将其内容进行渲染。
1.渲染器的介绍
渲染器的作用就是把虚拟DOM渲染为真实DOM
思考下,我们有一个虚拟 DOM,如何将它转换为真实 DOM
const vnode = {
tag: 'div',
props: {
onClick: () => alert('hello')
},
children: 'click me'
}
2.实现渲染函数renderer(只考虑创建没有考虑更新逻辑情况下)
-
两个参数。参数vnode表示虚拟 DOM 对象,container表示一个真实 DOM 元素,作为挂载点,渲染器会把虚拟 DOM 渲染到该挂载点
-
使用vnode.tag作为创建的dom标签el
-
遍历vnode.props,将属性 事件添加到DOM上(事件即给元素添加监听事件;)
-
处理 children(如果 children 是字符串,说明它是元素的文本子节点用createTextNode;如果children是数组则递归调用render函数渲染子节点并挂载到el元素下)
-
将元素添加到挂载节点container下
<div id="app"></div>
<script>
// 手写render函数将自己定义的vnode对象渲染到页面
/**
* @vnode 虚拟 DOM 对象
* @container 一个真实 DOM 元素,作为挂载点,渲染器会把虚拟 DOM 渲染到该挂载点
*/
function render(vnode, container) {
// 使用vnode.tag作为创建的dom标签el
let el = document.createElement(vnode.tag);
// 遍历vnode.props,将属性 事件添加到DOM上(事件即给元素添加监听事件;)
for (let key in vnode.props) {
// 判断如果为事件则将其设置到el中
if ((/^(on)/).test(key)) {
el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key]);
}
}
// 处理 children(字符串和数组)
if (typeof vnode.children === "string") {
el.appendChild(document.createTextNode(vnode.children));
} else if (Array.isArray(vnode.children)) { //是数组进行遍历并递归调用render方法
vnode.children.forEach(child => {
render(child, el);
});
}
// 将元素添加到挂载节点container下
container.appendChild(el);
}
// render函数测试
const container = document.getElementById('app')
const vnode = {
tag: 'div',
props: {
onClick: () => alert('hello')
},
// children: 'click me'
children: [{
tag: 'h1',
props: {
onClick: () => alert('h1')
},
children: '这是h1'
},
{
tag: 'span',
props: {
onClick: () => alert('span')
},
children: '这是span'
}]
}
render(vnode, container)
</script>