一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
我正在参加 码上掘金体验活动,详情:show出你的创意代码块
与真实DOM对应的 JavaScript 对象就叫做虚拟 DOM,虚拟可以通过一些巧妙的方法转换为真实 DOM ,操作虚拟 DOM 的代价远小于真实 DOM。今天我们来实现一下虚拟 DOM 的核心逻辑。
首先,我们的虚拟 DOM 是与真实 DOM 有相似性的,所以我们要根据现有的真实 DOM 结构来判断我们创建的虚拟 DOM 的关键属性有哪些。一个真实的 DOM 节点如下:
<div class="class-name">这是一些内容</div>
其中标签名是必须的,类名和文字内容是可选的,类名属于标签名的属性,文字内容是标签的子元素。于是我们根据位置可以大致得出一个虚拟 DOM 对象应该包含至少三个属性:tagName ,props ,children 。
那么,我们可以写个函数创建一个虚拟DOM对象了
const initVDOM = (tagName, { props = {}, children = [] } = {}) => {
const element = Object.create(null);
Object.assign(element, {
tagName,
props,
children,
});
return element;
}
如上所述,
- tagName 是一个字符串,他标志着这是某元素,某标签,我们通过
document.createElement(tagName)来创建对应的元素; - props 是元素的属性对象,它的 key-value 是 属性名-属性值 我们通过遍历这个对象,利用
node.setAttribute(key,value)来为标签添加属性; - children 是一个数组,它表示的是元素的子元素集合,子元素可能是一段文字,也可能是一个标签(对象);我们遍历这个数组,对每个子元素做数据类型的判断,若是文字或者数字,那么我们认为它是文本节点,利用
document.createTextNode(child)来创建文本节点,然后通过element.appendChild(child)来加入到父节点的子节点中;如果是元素(对象),那就像他父元素那样走一遍。
按照这个思想,我们可以写一下从虚拟 DOM 转换到真实 DOM 的逻辑函数来了
const render = (vNode) => {
// 如果虚拟DOM对象是数字或者字符串,那么就是一个文本节点
if (typeof vNode === 'string' || typeof vNode === 'number') {
return document.createTextNode(vNode)
}
// 元素节点
// 创建元素节点
const el = document.createElement(vNode.tagName);
// 设置属性
for (let [key, val] of Object.entries(vNode.props)) {
el.setAttribute(key, val);
}
// 设置子元素 子元素是一个数组;它可能是单个文本节点,可能是多个元素节点,但是总而言之它是一个节点数组,所以我们直接遍历这个数组,对子节点先渲染,然后添加到 el 的子节点中
for (let child of vNode.children) {
el.appendChild(render(child));
}
return el;
}
那么,我们既然现在已经有一个真实的 DOM 节点了,接下来就可以将他挂载到网页中啦!于是我们为这个节点找一个父节点,再写一个简单的挂载函数就可以在页面上看到它了
// html 文件
<body>
<!-- 父节点 -->
<div id="vm"></div>
</body>
<script>
// 这是我们的DOM对象
const vApp = h('div', {
props: {
id: 'app'
},
children: [
'sadfadfa',
h('h1', {
props: {
id: 'title'
},
children: ['hello world!']
})
]
})
// 挂载函数
const mount = ($node, $target) => {
return $target.appendChild($node)
}
// 渲染为真实 DOM 节点
const $app = render(vApp)
// 挂载我们的DOM节点到id为vm的节点中去
mount($app, document.getElementById('vm')) // 大功告成
</script>
就这样我们就完成了虚拟 DOM 对象到真实 DOM 节点的渲染、挂载了。但是,有一个很重要的步骤就是更新,现在的网页都是动态更新的,我们这个流程,每次修改 vApp 都会全量的渲染一次整个节点,所以,下期,我们将了解非常重要的diff算法将我们的效率降下来。
下面是本次 demo 的代码片段,可以修改代码中的vApp来查看效果 code.juejin.cn/pen/7088259…
以上就是本期文章的所有内容了,如果你能有什么感觉的话,请给我一些反馈吧,:Accept: 一键三连是最大的鼓[代码片段]励,多谢,我们下期再见!