简单补充一下vue template模板转为真实DOM的过程:
template -> compiler 编译 -> 渲染函数render(调用h函数) -> Vnode(虚拟节点) -> 真实元素 -> 渲染
接下来将通过代码展示实现过程:
// 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>
</head>
<body>
<div id="app"></div>
<script src="./render.js"></script>
<script>
let counter = 1
// compiler编译template后的结果
const vnode = h("div", {class: 'black'}, [
h("button", {onclick: function() {counter++; console.log(counter)}} , '+1'),
h("h2", null, counter)
])
mount(vnode, document.querySelector('#app'))
</script>
</body>
</html>
// render.js
// h函数的作用就是将compiler编译后的模板转为vnode(也就是js对象)
function h(tag, property, children) {
return {
tag,
property,
children
}
}
// 将vnode转为真实DOM
function mount(vnode, container) {
// 1. 将tag转为标签
const el = vnode.el = document.createElement(vnode.tag)
// 2. 给标签设置对应的属性
if (vnode.property) {
for (const key in vnode.property) {
const value = vnode.property[key]
// 点击事件
if (key.startsWith("on")) {
el.addEventListener(key.slice(2), value)
console.log(el.click)
} else {
el.setAttribute(key, value)
}
}
}
// 3. 处理children
if (vnode.children) {
if (typeof vnode.children === 'string' || typeof vnode.children === 'number') {
el.textContent = vnode.children
} else {
vnode.children.forEach(item => {
mount(item, el)
});
}
}
// 4. 将节点挂载到父节点上
container.appendChild(el)
}
以上呢就是render函数借助h函数是怎样的将compiler编译后的代码转为vnode并转为真实DOM实现的简易过程。
如有错误,欢迎指正!