javascript---将DOM结构转换成虚拟DOM虚拟DOM转换成真实的DOM结构虚拟DOM的实现
使⽤虚拟DOM的原因: 减少
将DOM结构转换成对象保存到内存中
<img /> => { tag: 'img'}
⽂本节点 => { tag: undefined, value: '⽂本节点' }
<img title="1" class="c" /> => { tag: 'img', data: { title = "1", class="c" } }
<div><img /></div> => { tag: 'div', children: [{ tag: 'div' }]}
根据上⾯可以写出虚拟DOM的数据结构
class VNode {
constructor(tag, data, value, type){
this.tag = tag && LowerCase()
this.data = data
this.value = value
this.children =[]
}
appendChild(vnode){
this.children.push(vnode)
}
}
可能⽤到的基础知识
判断元素的节点类型: deType
let nodeType = deType
if(nodeType == 1) {
// 元素类型
} else if (nodeType == 3) {
// 节点类型
}
获取元素类型的标签名和属性 && 属性中具体的键值对,保存在⼀个对象中
let nodeName = deName // 标签名
let attrs  = node.attributes // 属性
let _attrObj ={}// 保存各个具体的属性的键值对,相当于虚拟DOM中的data属性
for(let i =0, len = attrs.length; i< len; i++){
_attrObj[attrs[i].nodeName]= attrs[i].nodeValue
}
获取当前节点的⼦节点
let childNodes = node.childNodes
for(let i =0, len = childNodes.length; i < len; i++){
console.log(childNodes[i])
}
算法思路
使⽤document.querySelector获取要转换成虚拟DOM的模板
使⽤nodeType⽅法来获取是元素类型还是⽂本类型
若是元素类型
使⽤nodeName获取标签名
使⽤attributes获取属性名,并将具体的属性保存到⼀个对象_attrObj中
创建虚拟DOM节点
考虑元素类型是否有⼦节点,使⽤递归,将⼦节点的虚拟DOM存⼊其中
若是⽂本类型
直接创建虚拟DOM,不需要考虑⼦节点的问题
// 虚拟DOM的数据结构
class VNode{
constrctor(tag, data, value, type){
this.tag = tag && LowerCase()
this.data = data
this.value = value
this.children =[]
}
appendChild(vnode){
this.children.push(vnode)nodeselector
}
}
// 获取要转换的DOM结构
let root = document.querySelector('#root')
// 使⽤getVNode⽅法将真实的DOM结构转换成虚拟DOM
let vroot =getVNode(root)
以上写了虚拟DOM的数据结构,以及使⽤getVNode⽅法将真实DOM结构转换成虚拟DOM,下⾯开始逐步实现getVNode⽅法判断节点类型,并返回虚拟DOM
function getVNode(node){
// 获取节点类型
let nodeType = deType;
if(nodeType ==1){
// 元素类型: 获取其属性,判断⼦元素,创建虚拟DOM
}else if(nodeType ==3){
// ⽂本类型: 直接创建虚拟DOM
}
let _vnode =null;
return _vnode
}
下⾯根据元素类型和⽂本类型分别创建虚拟DOM
if(nodeType ==1){
// 标签名
let tag = deName
// 属性
let attrs = node.attributes
/*
属性转换成对象形式: <div title ="marron" class="1"></div>
{ tag: 'div', data: { title: 'marron', class: '1' }}
*/
let _data ={};// 这个_data就是虚拟DOM中的data属性
for(let i =0, len = attrs.length; i< attrs.len; i++){
_data[attrs[i].nodeName]= attrs[i].nodeValue
}
// 创建元素类型的虚拟DOM
_vnode =new VNode(tag, _data, undefined, nodeType)
// 考虑node的⼦元素
let childNodes = node.childNodes
for(let i =0, len = childNodes.length; i < len; i++){
_vnode.appendChild(getVNode(childNodes[i]))
}
}
// 接下来考虑⽂本类型
else if(nodeType ==3){
_vnode =new VNode(undefined, undefined, deValue, nodeType) }
总体代码
constructor(tag, data, value, type){
this.tag = tag && LowerCase()
this.data = data
this.value = value
this.children =[]
}
appendChild(vnode){
this.children.push(vnode)
}
}
function getVNode(node){
let nodeType = deType
let _vnode =null
if(nodeType ==1){
let tag = deName
let attrs = node.attributes
let _data ={}
for(let i =0, len = attrs.length; i < len; i++){
_data[attrs[i].nodeName]= attrs[i].nodeValue
}
_vnode =new VNode(tag, _data, undefined, nodeType)
let childNodes = node.childNodes
for(let i =0, len = childNodes.length; i < len; i++){
_vnode.appendChild(getVNode(childNodes[i]))
}
}else if(nodeType ==3){
_vnode =new VNode(undefined, undefined, deValue, nodeType) }
return _vnode
}
let root = document.querySelector('#root')
let vroot =getVNode(root)
console.log(vroot)
将虚拟DOM转换成真实的DOM结构
此过程就是上⾯的反过程
可能⽤到的知识点
创建⽂本节点
创建元素节点
给元素节点添加属性
node.setAttribute(attrName, attrValue)
给元素节点添加⼦节点
node.appendChild(node)
虚拟DOM的结构中,元素的节点类型存储在type中,根据type可以判断出是⽂本节点还是元素节点若为⽂本节点,直接返回⼀个⽂本节点ateTextNode(value)
若为元素节点
创建⼀个node节点:_node = ateElement(tag)
遍历虚拟DOM中的data属性,将其中的值赋给node节点
给当前节点添加⼦节点
具体实现
function parseVNode(vnode){
let type = pe
let _node =null
if(type ==3){
ateTextNode(vnode.value)
}else if(type ==1){
_node = ateElement(vnode.tag)
let data = vnode.data
let attrName,attrValue
Object.keys(data).forEach(key=>{
attrName = key
attrValue = data[key]
_node.setAttribute(attrName, attrValue)
})
// 考虑⼦元素
let children = vnode.children
children.forEach( subvnode =>{
_node.appendChild(parseVNode(subvnode))
})
}
return _node
}
验证:
let root =querySelector('#root')
let vroot =getVNode(root)
console.log(vroot)
let root1 =parseVNode(vroot)
console.log(root1)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。