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 && tag.toLowerCase()this.data = datathis.value = valuethis.type = typethis.children = []}appendChild(vnode){this.children.push(vnode)}
}

可能用到的基礎知識

  • 判斷元素的節點類型: node.nodeType
let nodeType = node.nodeType
if(nodeType == 1) {// 元素類型
} else if (nodeType == 3) {// 節點類型
}
  • 獲取元素類型的標簽名和屬性 && 屬性中具體的鍵值對,保存在一個對象中
let nodeName = node.nodeName	// 標簽名
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 && tag.toLowerCase()this.data = datathis.value = valuethis.type = typethis.children = []}appendChild(vnode) {this.children.push(vnode)}
}// 獲取要轉換的DOM結構
let root = document.querySelector('#root')
// 使用getVNode方法將 真實的DOM結構轉換成虛擬DOM
let vroot = getVNode(root)	

以上寫了虛擬DOM的數據結構,以及使用getVNode方法將真實DOM結構轉換成虛擬DOM,下面開始逐步實現getVNode方法

  • 判斷節點類型,并返回虛擬DOM
function getVNode(node){// 獲取節點類型let nodeType = node.nodeType;if(nodeType == 1){// 元素類型: 獲取其屬性,判斷子元素,創建虛擬DOM} else if(nodeType == 3) {// 文本類型: 直接創建虛擬DOM}let _vnode = null;return _vnode
}
  • 下面根據元素類型和文本類型分別創建虛擬DOM
if(nodeType == 1){// 標簽名let tag = node.nodeName// 屬性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.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)
}

總體代碼

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轉換成真實的DOM結構

此過程就是上面的反過程

可能用到的知識點

  • 創建文本節點
document.createTextNode(value)
  • 創建元素節點
document.createElement(tag)
  • 給元素節點添加屬性
node.setAttribute(attrName, attrValue)
  • 給元素節點添加子節點
node.appendChild(node)

算法思路

  • 虛擬DOM的結構中,元素的節點類型存儲在type中,根據type可以判斷出是文本節點還是元素節點
  • 若為文本節點,直接返回一個文本節點return document.createTextNode(value)
  • 若為元素節點
    • 創建一個node節點:_node = document.createElement(tag)
    • 遍歷虛擬DOM中的data屬性,將其中的值賦給node節點
    • 給當前節點添加子節點

具體實現

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
}

驗證:

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/250278.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/250278.shtml
英文地址,請注明出處:http://en.pswp.cn/news/250278.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

swap(a,b)值交換的4種方法

方法一&#xff1a;int tmp 0; tmp b;b a; a tmp; 方法二&#xff1a;a ab; b a-b; a a-b;方法三&#xff1a;a ^ b ^ a^ b;方法四&#xff1a;a ab-(ba);轉載于:https://www.cnblogs.com/vocaloid01/p/9514126.html

裝系統工具

安裝如果失敗,注意是不是工具的版本太老導致 系統分區工具: DiskGeniusPortable 刻錄工具: UlraISO rufus https://rufus.ie/ win32diskimager 轉載于:https://www.cnblogs.com/jiangfeilong/p/9937164.html

小程序WXML基本使用

數據綁定 <!--wxml--> <view> {{message}} </view> // page.js Page({data: {message: Hello MINA!} }) 列表渲染 <!--wxml--> <view wx:for"{{array}}"> {{item}} </view> // page.js Page({data: {array: [1, 2, 3, 4, 5]} })…

javascript --- vue中簡單的模板渲染

一層的渲染 將下面的模板中的mustache語法使用給定數據渲染. 模板如下 <div id"root"><div><div><p>{{name}} - {{message}}</p></div></div><p>{{name}}</p><p>{{msg}}</p> </div>數據如…

tomcat 虛擬路徑 與 虛擬主機配置

虛擬路徑配置 方法一&#xff1a;此方法需要重啟服務 打開下面文件 在host里面添加context標簽 <Context docBase"D:\test" path"/testServlet/aaaaa" reloadable"true" /> 瀏覽器訪問&#xff1a;http://172.16.6.103:1080/testServlet/a…

20172328 2018-2019《Java軟件結構與數據結構》第八周學習總結

20172328 2018-2019《Java軟件結構與數據結構》第八周學習總結 概述 Generalization 本周學習了二叉樹的另一種有序擴展&#xff1f;是什么呢&#xff1f;你猜對了&#xff01;ヾ(???)&#xff89;&#xff9e;就是堆。本章將講解堆的鏈表實現and數組實現&#xff0c;以及往…

javascript --- 函數的柯里化 Vue 2.x中柯里化的使用

函數式編程部分重點 參考資料: 函數式編程 柯里化 只傳遞給函數一部分參數來調用它,讓它返回一個函數去處理剩下的參數 var add function (x) {return function(y) {return x y} }var increment add(1) var addTen add(10)increment(2) // 3addTen(10) // 12判斷元素:V…

MYSQL重置ROOT密碼

背景 mysql 服務器長時間未使用&#xff0c;管理員當時設置的root 密碼忘記&#xff0c;需要重置 root 密碼&#xff0c;并加以妥善保存。 步驟 關閉 mysql 服務以跳過密碼驗證的方式啟動 mysql 服務mysqld --skip-grant-tables本地登陸后設置新的root 密碼 update mysql.user …

javascript --- Vue初始化 模板渲染

不帶響應式的Vue縮減實現 模板 現有模板如下: <div id "app"><div class"c1"><div titlett1 id"id">{{ name }}</div><div titlett2 >{{age}}</div><div>hello3</div></div><ul>…

#RANK_1 極其簡單的遞歸——騎士與金幣

2000:金幣 總時間限制: 1000ms內存限制: 65536kB描述國王將金幣作為工資&#xff0c;發放給忠誠的騎士。第一天&#xff0c;騎士收到一枚金幣&#xff1b;之后兩天&#xff08;第二天和第三天&#xff09;里&#xff0c;每天收到兩枚金幣&#xff1b;之后三天&#xff08;第四、…

動手動腦4

import java.io.*; public class ThrowMultiExceptionsDemo { public static void main(String[] args) { try { throwsTest(); } catch(IOException e) { System.out.println("捕捉異常"); }}private static void throwsTest() throws ArithmeticException,IOExcep…

javascript --- 對象原型

對象原型 參考 - MDN Javascript中的原型 在Javascript中,每一個函數都有一個特殊的屬性,叫做原型 下面獲取函數的原型fn.prototype function f1(){} console.log(f1.prototype) /*{constructor: f f1()__proto__:{constructor: f Object()__defineGetter__: f __defineGe…

從零認識單片機(9)

keil軟件&#xff1a; IDE:IDE是集成開發環境&#xff0c;就是用來開發的完整的軟件系統。 keil和mdk: keil:只能用來開發單片機 mdk:基于keil 拓展ARM的開發&#xff0c;主要用來開發ARM-cortex-m系列單片機的程序。 使用keil打開已有的工程項目&#xff1a; 1、IDE開發軟件&a…

javascript --- vue2.x中原型的使用(攔截數組方法) 響應式原理(部分)

說明 在Vue2.x中,利用了對原型鏈的理解,巧妙的利用JavaScript中的原型鏈,實現了數組的pop、push、shift、unshift、reverse、sort、splice等的攔截. 你可能需要的知識 參考 - MDN 原型鏈 JavaScript常被描述為一種基于原型的語言(prototype-based language),每個對象擁有一…

dubbo-admin構建報錯

dubbo-admin構建報錯 意思是maven庫里沒有dubbo2.5.4-SNAPSHOT.jar這個版本的dubbo的jar包&#xff0c;把dubbo-admin項目的pom.xml的   <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>${proje…

javascript --- 手寫Promise、快排、冒泡、單例模式+觀察者模式

手寫promise 一種異步的解決方案, 參考 Promise代碼基本結構 function Promise(executor){this.state pending;this.value undefined;this.reason undefined;function resolve(){}function reject(){} } module.exports Promisestate保存的是當前的狀態,在Promise狀態發…

PyCharm 通過Github和Git上管理代碼

1.Pycharm中設置如圖: 2.配置Git,通過網頁 https://www.git-scm.com/download/win 下載 3. 轉載于:https://www.cnblogs.com/0909/p/9956406.html

【BZOJ】2395: [Balkan 2011]Timeismoney

題解 最小乘積生成樹&#xff01; 我們把&#xff0c;x的總和和y的總和作為x坐標和y左邊&#xff0c;畫在坐標系上 我們選擇兩個初始點&#xff0c;一個是最靠近y軸的A&#xff0c;也就是x總和最小&#xff0c;一個是最靠近x軸的B&#xff0c;也就是y總和最小 連接兩條直線&…

http --- http與https相關概念小結

網絡協議 參考 HTTP的特性 HTTP協議構建于TCP/IP協議之上,是一個應用層協議,默認端口是80HTTP是無連接無狀態的 HTTP報文 請求報文 HTTP協議是以ASCII碼傳輸,建立在 TCP/IP 協議之上的應用層規范。規范把HTTP請求分為三個部分:狀態行、請求頭、消息主體。 <method>…

Spring AOP注解方式實現

簡介 上文已經提到了Spring AOP的概念以及簡單的靜態代理、動態代理簡單示例&#xff0c;鏈接地址&#xff1a;https://www.cnblogs.com/chenzhaoren/p/9959596.html 本文將介紹Spring AOP的常用注解以及注解形式實現動態代理的簡單示例。 常用注解 aspect&#xff1a;定義切面…