日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

javascript --- 将DOM结构转换成虚拟DOM 虚拟DOM转换成真实的DOM结构

發(fā)布時(shí)間:2023/12/10 javascript 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javascript --- 将DOM结构转换成虚拟DOM 虚拟DOM转换成真实的DOM结构 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

虛擬DOM的實(shí)現(xiàn)

使用虛擬DOM的原因: 減少回流與重繪

將DOM結(jié)構(gòu)轉(zhuǎn)換成對(duì)象保存到內(nèi)存中

<img /> => { tag: 'img'}

文本節(jié)點(diǎn) => { tag: undefined, value: '文本節(jié)點(diǎn)' }

<img title="1" class="c" /> => { tag: 'img', data: { title = "1", class="c" } }

<div><img /></div> => { tag: 'div', children: [{ tag: 'div' }]}

根據(jù)上面可以寫出虛擬DOM的數(shù)據(jù)結(jié)構(gòu)

class VNode {constructor(tag, data, value, type) {this.tag = tag && tag.toLowerCase()this.data = datathis.value = valuethis.type = typethis.children = []}appendChild(vnode){this.children.push(vnode)} }

可能用到的基礎(chǔ)知識(shí)

  • 判斷元素的節(jié)點(diǎn)類型: node.nodeType
let nodeType = node.nodeType if(nodeType == 1) {// 元素類型 } else if (nodeType == 3) {// 節(jié)點(diǎn)類型 }
  • 獲取元素類型的標(biāo)簽名和屬性 && 屬性中具體的鍵值對(duì),保存在一個(gè)對(duì)象中
let nodeName = node.nodeName // 標(biāo)簽名 let attrs = node.attributes // 屬性 let _attrObj = {} // 保存各個(gè)具體的屬性的鍵值對(duì),相當(dāng)于虛擬DOM中的data屬性 for(let i =0, len = attrs.length; i< len; i++){_attrObj[attrs[i].nodeName] = attrs[i].nodeValue }
  • 獲取當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)
let childNodes = node.childNodes for(let i = 0, len = childNodes.length; i < len; i++){console.log(childNodes[i]) }

算法思路

  • 使用document.querySelector獲取要轉(zhuǎn)換成虛擬DOM的模板
  • 使用nodeType方法來(lái)獲取是元素類型還是文本類型
  • 若是元素類型
    • 使用nodeName獲取標(biāo)簽名
    • 使用attributes獲取屬性名,并將具體的屬性保存到一個(gè)對(duì)象_attrObj中
    • 創(chuàng)建虛擬DOM節(jié)點(diǎn)
    • 考慮元素類型是否有子節(jié)點(diǎn),使用遞歸,將子節(jié)點(diǎn)的虛擬DOM存入其中
  • 若是文本類型
    • 直接創(chuàng)建虛擬DOM,不需要考慮子節(jié)點(diǎn)的問(wèn)題
// 虛擬DOM的數(shù)據(jù)結(jié)構(gòu) class VNode{constrctor(tag, data, value, type){this.tag = tag && tag.toLowerCase()this.data = datathis.value = valuethis.type = typethis.children = []}appendChild(vnode) {this.children.push(vnode)} }// 獲取要轉(zhuǎn)換的DOM結(jié)構(gòu) let root = document.querySelector('#root') // 使用getVNode方法將 真實(shí)的DOM結(jié)構(gòu)轉(zhuǎn)換成虛擬DOM let vroot = getVNode(root)

以上寫了虛擬DOM的數(shù)據(jù)結(jié)構(gòu),以及使用getVNode方法將真實(shí)DOM結(jié)構(gòu)轉(zhuǎn)換成虛擬DOM,下面開(kāi)始逐步實(shí)現(xiàn)getVNode方法

  • 判斷節(jié)點(diǎn)類型,并返回虛擬DOM
function getVNode(node){// 獲取節(jié)點(diǎn)類型let nodeType = node.nodeType;if(nodeType == 1){// 元素類型: 獲取其屬性,判斷子元素,創(chuàng)建虛擬DOM} else if(nodeType == 3) {// 文本類型: 直接創(chuàng)建虛擬DOM}let _vnode = null;return _vnode }
  • 下面根據(jù)元素類型和文本類型分別創(chuàng)建虛擬DOM
if(nodeType == 1){// 標(biāo)簽名let tag = node.nodeName// 屬性let attrs = node.attributes/*屬性轉(zhuǎn)換成對(duì)象形式: <div title ="marron" class="1"></div>{ tag: 'div', data: { title: 'marron', class: '1' }}*/let _data = {}; // 這個(gè)_data就是虛擬DOM中的data屬性for(let i =0, len = attrs.length; i< attrs.len; i++){_data[attrs[i].nodeName] = attrs[i].nodeValue}// 創(chuàng)建元素類型的虛擬DOM_vnode = new VNode(tag, _data, undefined, nodeType)// 考慮node的子元素let childNodes = node.childNodesfor(let i =0, len = childNodes.length; i < len; i++){_vnode.appendChild(getVNode(childNodes[i]))} } // 接下來(lái)考慮文本類型 else if(nodeType == 3){_vnode = new VNode(undefined, undefined, node.nodeValue, nodeType) }

總體代碼

class VNode {constructor(tag, data, value, type) {this.tag = tag && tag.toLowerCase()this.data = datathis.value = valuethis.type = typethis.children = []}appendChild(vnode){this.children.push(vnode)} }function getVNode(node) {let nodeType = node.nodeTypelet _vnode = nullif (nodeType == 1) {let tag = node.nodeNamelet attrs = node.attributeslet _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.childNodesfor (let i = 0, len = childNodes.length; i < len; 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)

將虛擬DOM轉(zhuǎn)換成真實(shí)的DOM結(jié)構(gòu)

此過(guò)程就是上面的反過(guò)程

可能用到的知識(shí)點(diǎn)

  • 創(chuàng)建文本節(jié)點(diǎn)
document.createTextNode(value)
  • 創(chuàng)建元素節(jié)點(diǎn)
document.createElement(tag)
  • 給元素節(jié)點(diǎn)添加屬性
node.setAttribute(attrName, attrValue)
  • 給元素節(jié)點(diǎn)添加子節(jié)點(diǎn)
node.appendChild(node)

算法思路

  • 虛擬DOM的結(jié)構(gòu)中,元素的節(jié)點(diǎn)類型存儲(chǔ)在type中,根據(jù)type可以判斷出是文本節(jié)點(diǎn)還是元素節(jié)點(diǎn)
  • 若為文本節(jié)點(diǎn),直接返回一個(gè)文本節(jié)點(diǎn)return document.createTextNode(value)
  • 若為元素節(jié)點(diǎn)
    • 創(chuàng)建一個(gè)node節(jié)點(diǎn):_node = document.createElement(tag)
    • 遍歷虛擬DOM中的data屬性,將其中的值賦給node節(jié)點(diǎn)
    • 給當(dāng)前節(jié)點(diǎn)添加子節(jié)點(diǎn)

具體實(shí)現(xiàn)

function parseVNode(vnode){let type = vnode.typelet _node = nullif(type == 3){return document.createTextNode(vnode.value)} else if (type == 1){_node = document.createElement(vnode.tag)let data = vnode.datalet attrName,attrValueObject.keys(data).forEach(key=>{attrName = keyattrValue = data[key]_node.setAttribute(attrName, attrValue)})// 考慮子元素let children = vnode.childrenchildren.forEach( subvnode =>{_node.appendChild(parseVNode(subvnode))})}return _node }

驗(yàn)證:

let root = querySelector('#root') let vroot = getVNode(root) console.log(vroot) let root1 = parseVNode(vroot) console.log(root1)

總結(jié)

以上是生活随笔為你收集整理的javascript --- 将DOM结构转换成虚拟DOM 虚拟DOM转换成真实的DOM结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。