标题真实dom转换为虚拟dom的简单实现
首先给出虚拟dom的数据结构。
function vnode(tag, data) {
this.tag = tag;
this.data = data;
this.childern = [];
}
一个虚拟节点拥有标签名(tag),属性数据(data),和子节点(childern)。
我们再为这个对象添加一个方法,用来增加子节点。
vnode.prototype.addChild = function (node) {
this.childern.push(node);
}
定义好了虚拟节点的对象,接下就去获取真实的节点。
var b = document.getElementsByTagName('body')[0]
var fragment = document.createDocumentFragment()
var vnodelist = []
while (b.firstChild) {
fragment.appendChild(b.firstChild)
}
var nodelist = fragment.childNodes;
nodelist = Array.prototype.slice.call(nodelist);
首先定位到body节点,创建一个文档碎片对象,我们将body节点下的所有节点加入到文档碎片中,再将文档碎片中的所有孩子节点拿出来,强制转换成一个节点数组(nodelist),这样就拿到了body下面的所有节点。
然后实现真实节点到虚拟节点的转变。
function createvnode(node) {
let v = null;
if (node.nodeType === 1) {
let tag = node.nodeName.toLowerCase();
let data = {};
let attribute = node.attributes;
[...attribute].forEach(attr => {
var { name, value } = attr;
data[name] = value;
})
// let text = node.innerText;
v = new vnode(tag,data);
nodechildern = node.childNodes;
if(nodechildern){
[...nodechildern].forEach(kid => {
v.addChild(createvnode(kid))
})
}
} else if(node.nodeType === 3){
v = new vnode('text',node.nodeValue)
}
return v;
}
如果是文本节点,我们就直接设置其tag为text,data为文本的内容。
最后遍历节点数组,将所有节点转变为虚拟节点。
nodelist.forEach(node => {
vnodelist.push(createvnode(node));
})
完整的代码如下。
window.onload = function () {
var b = document.getElementsByTagName('body')[0]
var fragment = document.createDocumentFragment()
var vnodelist = []
while (b.firstChild) {
fragment.appendChild(b.firstChild)
}
var nodelist = fragment.childNodes;
nodelist = Array.prototype.slice.call(nodelist);
function vnode(tag, data) {
this.tag = tag;
this.data = data;
// this.text = text;
this.childern = [];
}
vnode.prototype.addChild = function (node) {
this.childern.push(node);
}
function createvnode(node) {
let v = null;
if (node.nodeType === 1) {
let tag = node.nodeName.toLowerCase();
let data = {};
let attribute = node.attributes;
[...attribute].forEach(attr => {
var { name, value } = attr;
data[name] = value;
})
// let text = node.innerText;
v = new vnode(tag,data);
nodechildern = node.childNodes;
if(nodechildern){
[...nodechildern].forEach(kid => {
v.addChild(createvnode(kid))
})
}
} else if(node.nodeType === 3){
v = new vnode('text',node.nodeValue)
}
return v;
}
nodelist.forEach(node => {
vnodelist.push(createvnode(node));
})
for(var i = 0;i<vnodelist.length;i++){
console.log(vnodelist[i])
}
b.appendChild(fragment)
}
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>
<script src="./dom_to_vdom.js"></script>
<div id='app'>
<span>11</span>
<p>12</p>
</div>
</body>
</html>
最后得到的结果如图。