如何將HTML字符轉(zhuǎn)換為DOM節(jié)點(diǎn)并動態(tài)添加到文檔中詳解
前言
將字符串動態(tài)轉(zhuǎn)換為DOM節(jié)點(diǎn),在開發(fā)中經(jīng)常遇到,尤其在模板引擎中更是不可或缺的技術(shù)。
字符串轉(zhuǎn)換為DOM節(jié)點(diǎn)本身并不難,本篇文章主要涉及兩個主題:
1 字符串轉(zhuǎn)換為HTML DOM節(jié)點(diǎn)的基本方法及性能測試
2 動態(tài)生成的DOM節(jié)點(diǎn)添加到文檔中的方法及性能測試
本文的示例: 有如下代碼段
<!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='container'> <!-- 動態(tài)添加div <div class='child'> XXX</div> --> </div> </body> </html>
任務(wù)是編寫一個JavaScript函數(shù),接收一個文本內(nèi)容,動態(tài)生成一個包含該文本的div,返回該Node。下面話不多說了,來隨著小編一起看看詳細(xì)的介紹吧。
1.1 動態(tài)創(chuàng)建Node
1.1.1 innerHTML
第一種方法,我們使用document.createElement方法創(chuàng)建新的元素,然后利用innerHTML將字符串注入進(jìn)去,最后返回firstChild,得到動態(tài)創(chuàng)建的Node。
<script>
function createNode(txt) {
const template = `<div class='child'>${txt}</div>`;
let tempNode = document.createElement('div');
tempNode.innerHTML = template;
return tempNode.firstChild;
}
const container = document.getElementById('container');
container.appendChild(createNode('hello'));
</script>
下面我們看第二種方法
1.1.2 DOMParser
DOMParser 實(shí)例的parseFromString方法可以用來直接將字符串轉(zhuǎn)換為document 文檔對象。有了document之后,我們就可以利用各種DOM Api來進(jìn)行操作了。
function createDocument(txt) {
const template = `<div class='child'>${txt}</div>`;
let doc = new DOMParser().parseFromString(template, 'text/html');
let div = doc.querySelector('.child');
return div;
}
const container = document.getElementById('container');
container.appendChild(createDocument('hello'));
1.1.2 DocumentFragment
DocumentFragment 對象表示一個沒有父級文件的最小文檔對象。它被當(dāng)做一個輕量版的 Document 使用,用于存儲已排好版的或尚未打理好格式的XML片段。最大的區(qū)別是因為DocumentFragment不是真實(shí)DOM樹的一部分,它的變化不會引起DOM樹的重新渲染的操作(reflow) ,且不會導(dǎo)致性能等問題。
利用document.createRange().createContextualFragment方法,我們可以直接將字符串轉(zhuǎn)化為DocumentFragment對象。
function createDocumentFragment(txt) {
const template = `<div class='child'>${txt}</div>`;
let frag = document.createRange().createContextualFragment(template);
return frag;
}
const container = document.getElementById('container');
container.appendChild(createDocumentFragment('hello'));
這里要注意的是我們直接將生成的DocumentFragment對象插入到目標(biāo)節(jié)點(diǎn)中,這會將其所有自己點(diǎn)插入到目標(biāo)節(jié)點(diǎn)中,不包含自身。我們也可以使用
frag.firstChild
來獲取生成的div。
1.1.3 性能測試
下面我們來簡單比對下上面三種方法的性能,只是測試生成單個節(jié)點(diǎn),在實(shí)際使用中并不一定有實(shí)際意義。
先測試createNode。
function createNode(txt) {
const template = `<div class='child'>${txt}</div>`;
let start = Date.now();
for (let i = 0; i < 1000000; i++) {
let tempNode = document.createElement('div');
tempNode.innerHTML = template;
let node = tempNode.firstChild;
}
console.log(Date.now() - start);
}
createNode('hello');
測試100萬個Node生成,用時 6322。
再來測試createDocument。
function createDocument(txt) {
const template = `<div class='child'>${txt}</div>`;
let start = Date.now();
for (let i = 0; i < 1000000; i++) {
let doc = new DOMParser().parseFromString(template, 'text/html');
let div = doc.firstChild;
}
console.log(Date.now() - start);
}
createDocument('hello');
測試100萬個Node生成,用時 55188。
最后來測試createDocumentFragment.
function createDocumentFragment(txt) {
const template = `<div class='child'>${txt}</div>`;
let start = Date.now();
for (let i = 0; i < 1000000; i++) {
let frag = document.createRange().createContextualFragment(template);
}
console.log(Date.now() - start);
}
createDocumentFragment();
測試100萬個Node生成,用時 6210。
createDocumentFragment方法和createNode方法,在這輪測試中不相上下。下面我們看看將生成的DOM元素動態(tài)添加到文檔中的方法。
1.2.0 批量添加節(jié)點(diǎn)
被動態(tài)創(chuàng)建出來的節(jié)點(diǎn)大多數(shù)情況都是要添加到文檔中,顯示出來的。下面我們來介紹并對比幾種常用的方案。
下面我們批量添加的方法都采用createDocumentFragment方法。
1.2.1 直接append
直接append方法,就是生成一個節(jié)點(diǎn)就添加到文檔中,當(dāng)然這會引起布局變化,被普遍認(rèn)為是性能最差的方法。
const template = "<div class='child'>hello</div>";
function createDocumentFragment() {
let frag = document.createRange().createContextualFragment(template);
return frag;
}
// createDocumentFragment();
const container = document.getElementById('container');
let start = Date.now();
for (let i = 0; i < 100000; i++) {
container.appendChild(createDocumentFragment());
}
console.log(Date.now() - start);
上面的代碼我們測算動態(tài)添加10萬個節(jié)點(diǎn)。結(jié)果如下:

測試1000個節(jié)點(diǎn)耗時20毫秒,測試10000個節(jié)點(diǎn)耗時10001毫秒,測試100000個節(jié)點(diǎn)耗時46549毫秒。
1.2.2 DocumentFragment
上面我們已經(jīng)介紹過DocumentFragment了,利用它轉(zhuǎn)換字符串。下面我們利用該對象來作為臨時容器,一次性添加多個節(jié)點(diǎn)。
利用document.createDocumentFragment()方法可以創(chuàng)建一個空的DocumentFragment對象。
const template = "<div class='child'>hello</div>";
function createDocumentFragment() {
let frag = document.createRange().createContextualFragment(template);
return frag;
}
// createDocumentFragment();
const container = document.getElementById('container');
let fragContainer = document.createDocumentFragment();
let start = Date.now();
for (let i = 0; i < 1000; i++) {
fragContainer.appendChild(createDocumentFragment());
}
container.appendChild(fragContainer);
console.log(Date.now() - start);
測試1000個節(jié)點(diǎn)耗時25毫秒,10000個節(jié)點(diǎn)耗時2877毫秒,100000個節(jié)點(diǎn)瀏覽器卡死。
1.3 小結(jié)
簡單了介紹了幾種方法,并沒有什么技術(shù)含量。但是從動態(tài)添加節(jié)點(diǎn)來看,網(wǎng)上說的DocumentFragment方法性能遠(yuǎn)遠(yuǎn)好于直接append的說法在我的測試場景中并不成立。
DocumentFragment正確的應(yīng)用場景應(yīng)該是作為虛擬DOM容器,在頻繁修改查詢但是并不需要直接渲染的場景中。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- javascript 獲取HTML DOM父、子、臨近節(jié)點(diǎn)
- html dom節(jié)點(diǎn)操作(獲取/修改/添加或刪除)
- Js 獲取HTML DOM節(jié)點(diǎn)元素的方法小結(jié)
- 獲取HTML DOM節(jié)點(diǎn)元素的方法的總結(jié)
- 用于節(jié)點(diǎn)操作的API,顛覆原生操作HTML DOM節(jié)點(diǎn)的API
- JavaScript操作HTML DOM節(jié)點(diǎn)的基礎(chǔ)教程
- JavaScript DOM節(jié)點(diǎn)操作實(shí)例小結(jié)(新建,刪除HTML元素)
- [js高手之路]HTML標(biāo)簽解釋成DOM節(jié)點(diǎn)的實(shí)現(xiàn)方法
相關(guān)文章
微信小程序使用picker實(shí)現(xiàn)時間和日期選擇框功能【附源碼下載】
這篇文章主要介紹了微信小程序使用picker實(shí)現(xiàn)時間和日期選擇框功能,結(jié)合實(shí)例形式分析了微信小程序picker組件進(jìn)行日期與時間選擇的相關(guān)操作技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2017-12-12
關(guān)于JS控制代碼暫停的實(shí)現(xiàn)方法分享
關(guān)于JS控制代碼暫停的工作總結(jié),需要的朋友可以參考下2012-10-10
如何解決日期函數(shù)new Date()瀏覽器兼容性問題
這篇文章主要介紹了如何解決日期函數(shù)new Date()瀏覽器兼容性問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-09-09
如何利用JavaScript?實(shí)現(xiàn)繼承
這篇文章主要介紹了如何利用JavaScript?實(shí)現(xiàn)繼承,JavaScript?在編程語言界是個特殊種類,它和其他編程語言很不一樣,JavaScript可以在運(yùn)行的時候動態(tài)地改變某個變量的類型,下面小編將繼續(xù)介紹JavaScript如何實(shí)現(xiàn)繼承,需要的朋友可以參考下2022-02-02
JS/HTML5游戲常用算法之路徑搜索算法 隨機(jī)迷宮算法詳解【普里姆算法】
這篇文章主要介紹了JS/HTML5游戲常用算法之路徑搜索算法 隨機(jī)迷宮算法,結(jié)合實(shí)例形式詳細(xì)分析了針對迷宮游戲路徑搜索算法的普里姆算法相關(guān)原理、實(shí)現(xiàn)方法及操作注意事項,需要的朋友可以參考下2018-12-12
JavaScript實(shí)現(xiàn)商品放大鏡效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)商品放大鏡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10
TypeScript中使用getElementXXX()的示例代碼
這篇文章主要介紹了TypeScript中使用getElementXXX()的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09

