初识渲染器
我们已经知道什么是虚拟 DOM 了,那么,虚拟 DOM 该如何变成真实的 DOM 呢?这个时候我们就要使用渲染器了
渲染器的作用
渲染器是非常重要的一个角色,我们所使用的 Vue.js 组件都是要依赖渲染器来工作,这是一个非常重要的工作环节,这里我们初步了解一下渲染器的工作原理。
假如我们有如下虚拟 DOM:
const vnode = {
tag: "div",
props: {
onClick: () => {
alert("hello");
},
},
children: "cilck me",
};
相信大家都很明确上述虚拟 DOM 要处理怎样的事情,首先我们可以看到他是一个树形结构的 JavaScript 对象,我们需要有一个渲染函数,他接受的参数就是上述类型的 JavaScript 对象,然后将其转换成一个真实的 DOM,放置在页面上,
接下来,我们编写一个渲染器函数,把上面这段虚拟 DOM 渲染为真实的 DOM:
function renderer(vnode, container) {
// 使用 vnode.tag 作为标签名称创建 DOM 元素
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(), // 事件名称 onClick --->click
vnode.props[key] // 事件处理函数
);
}
}
// 处理 children
if (typeof vnode.children === "string") {
// 如果 children 是字符串,说明它是元素的文本子节点
el.appendChild(document.createTextNode(vnode.children));
} else if (Array.isArray(vnode.children)) {
// 递归地调用 renderer 函数渲染子节点,使用当前元素 el 作为挂载点
vnode.children.forEach((child) => renderer(child, el));
}
// 将元素添加到挂载点下
container.appendChild(el);
}
结合代码中的注释,我们大致可以了解到这个渲染函数的执行机制,他接收了如下两个参数:
vnode:虚拟 DOM 对象
container:一个真实的 DOM 元素,他作为虚拟 DOM 的挂载点。
最后我们执行渲染函数
renderer(vnode, document.body); //以body作为挂载点
梳理渲染思路
现在我们回过头来分析渲染器 renderer 的实现思路,总体来说分为三步。 1.创建元素:把 vnode.tag 作为标签名称来创建 DOM 元素。 2.为元素添加属性和事件:遍历 vnode.props 对象,如果 key 以 on 字符开头,说明它是一个事件,把字符 on 截取掉后再调用 toLowerCase 函数将事件名称小写化,最终得到合法的事件名称,例如 onClick 会变成 click,最后调用 addEventListener 绑定事件处理函数。 3.处理 children:如果 children 是一个数组,就递归地调用 renderer 继续渲染,注意,此时我们要把刚刚创建的元素作为挂载点(父节点);如果 children 是字符串,则使用 createTextNode 函数创建一个文本节点,并将其添加到新创建的元素内。