参考链接 www.bilibili.com/video/BV1LE…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root">
<div class="my">
<div title="tt1" id="id">hello1</div>
<div title="tt2">hello2</div>
<div title="tt3">hello3</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
</div>
<script>
/**
* 文本节点 => { tag: undefined, value: '文本节点内容' }
* 元素节点<div title="1" class="c"> <span>123 </span> </div> => {tag: 'div', data: { title: '1', class: 'c' }, children: [{ tag: 'span', value:123}]}
*/
class VNode {
constructor(tag, data, value, type) {
this.tag = tag && tag.toLowerCase();
this.data = data;
this.value = value;
this.type = type;
this.children = [];
}
appendChild(vnode) {
this.children.push(vnode);
}
}
/**
* 使用递归 来遍历 DOM 元素, 生成 虚拟 DOM
* @param node 真实的Dom节点
* @returns 虚拟 DOM
*/
function getVNode(node) {
let nodeType = node.nodeType;
let _vnode = null;
if (nodeType === 1) {
let nodeName = node.nodeName;
let attrs = node.attributes;
let _attrObj = {};
for (let i = 0; i < attrs.length; i++) {
_attrObj[attrs[i].nodeName] = attrs[i].nodeValue;
}
_vnode = new VNode(nodeName, _attrObj, undefined, nodeType);
// 考虑 node 的子元素
let childNodes = node.childNodes;
for (let i = 0; i < childNodes.length; i++) {
_vnode.appendChild(getVNode(childNodes[i])); // 递归
}
} else if (nodeType === 3) {
_vnode = new VNode(undefined, undefined, node.nodeValue, nodeType);
}
return _vnode;
}
let root = document.querySelector('#root');
let vroot = getVNode(root);
// console.log('vroot', vroot);
/**
* 将 vNode 转换为真正的 DOM
* @param vnode 虚拟Dom
* @returns 真实的Dom
*/
function parseVNode(vnode) {
// 创建 真实的 DOM
let type = vnode.type;
let _node = null;
if (type === 3) {
return document.createTextNode(vnode.value); // 创建文本节点
} else if (type === 1) {
_node = document.createElement(vnode.tag);
// 属性
let data = vnode.data;
Object.keys(data).forEach((key) => {
let attrName = key;
let attrValue = data[key];
_node.setAttribute(attrName, attrValue);
});
// 子元素
let children = vnode.children;
children.forEach(subvnode => {
_node.appendChild(parseVNode(subvnode)); // 递归转换子元素 ( 虚拟 DOM )
});
return _node;
}
}
let dom2 = parseVNode(vroot);
console.log('dom2', dom2);
</script>
</body>
</html>