深入理解javascript描述元素內容的5個屬性


前面的話

<p>This is a <i>simple</i> document</p>

  上面這行代碼中,<p>元素的內容是什么呢?答案一:內容是HTML字符串"This is a <i>simple</i> document";答案二:內容是純文本字符串"This is a simple document";答案三:內容是一個Text文本節點、一個包含了Text文本子節點的Element元素節點和另外一個Text文本節點

  三個答案都正確,不同的答案從不同的角度描述了元素內容。本文將詳細介紹描述元素內容的5個屬性

 

innerHTML

  innerHTML屬性可讀可寫。在讀模式下,返回與調用元素的所有子節點(包括元素、注釋和文本節點)對應的HTML標記;在寫模式下,innerHTML會根據指定的值創建新的DOM樹,然后用這個DOM樹完全替換調用元素原先的所有子節點

  [注意]IE8-瀏覽器會將所有標簽轉換成大寫形式,且不包含空白文本節點;而其他瀏覽器則原樣返回

<p id="test">This is a <i>simple</i> document</p>
<script>
console.log(test.innerHTML);//'This is a <i>simple</i> document'
test.innerHTML = 123;
console.log(test.innerHTML);//'123'    
</script>

  如果將innerHTML屬性設為空,等於刪除所有它包含的所有節點

<p id="test">This is a <i>simple</i> document</p>
<script>
test.innerHTML = '';
console.log(test.childNodes.length);//0
</script>

  [注意]在IE9-瀏覽器中,不支持innerHTML的屬性有:<col>、<colgroup>、<frameset>、<head>、<html>、<style>、<table>、<tbody>、<thead>、<tfoot>、<tr>。在IE8-瀏覽器中<title>元素也沒有該屬性

<table id="test"></table>
<script>
test.innerHTML = '1'
//在IE9-瀏覽器中報錯,其他瀏覽器返回1
console.log(test.innerHTML);
</script>

  無論什么時候,只要使用innerHTML從外部插入HTML,都應該首先以可靠的方式處理HTML。IE瀏覽器提供了window.toStaticHTML()方法,這個方法接收一個參數,即一個HTML字符串;返回一個經過無害處理后的版本——從源HTML中刪除所有腳本節點和事件處理程序屬性

var text = "<a href='#' onclick = 'alert(\"hi\");'>Click Me</a>";
var sanitized = window.toStaticHTML(text);
//只有IE支持
console.log(sanitized);//<a href="#">Click Me</a>

效率

  在元素上設置innerHTML屬性調用了Web瀏覽器的解析器,通常設置innerHTML效率非常髙,甚至在指定的值需要解析時效率也是相當不錯

<ul id="test1"></ul>
<ul id="test2"></ul>
<script>
console.time("time");
for(var i = 0; i < 10000;i++){
    var oLi = document.createElement('li');
    test1.appendChild(oLi);   
}
//15.842ms
console.timeEnd('time');
/****************************/
console.time("time");
var sHtml = '';
for(var i = 0; i < 10000; i++){
    sHtml += '<li></li>';
}
test2.innerHTML = sHtml;
//5.373ms
console.timeEnd('time');
</script>

  從上面可以看出,使用innerHTML比appendChild()的性能高出不少

  [注意]對innerHTML屬性用“+=”操作符重復追加一小段文本通常效率低下,因為它既要序列化又要解析

<ul id="test"></ul>
<script>
console.time("time");
for(var i = 0; i < 10000; i++){
    test.innerHTML += '<li></li>';
}
//time: 50416.330ms
console.timeEnd('time');
</script>

  可以看出,對innerHTML屬性使用'+='操作符的性能嚴重低下,所以一定不要這么使用

 

outerHTML

  outerHTML同樣可讀可寫,與innerHTML相比,它包含被查詢元素的開始和結束標簽。在讀模式下outerHTML返回調用它的元素及所有子節點的HTML標簽;在寫模式下,outerHTML會根據指定的HTML字符串創建新的DOM子樹,然后用這個DOM子樹完全替換調用元素 

  [注意]IE8-瀏覽器會將所有標簽轉換成大寫形式,且不包含空白文本節點;而其他瀏覽器則原樣返回

<p id="test">This is a <i>simple</i> document</p>
<script>
console.log(test.outerHTML);//<p id="test">This is a <i>simple</i> document</p>
test.outerHTML = '<div id="test"></div>';
console.log(test.outerHTML);//'<div id="test"></div>'
</script>

 

innerText

  innerText屬性可以操作元素中包含的所有文本內容,包括子文檔樹中的文本。在通過innerText讀取值時,它會按照由淺入深地順序,將子文檔樹中的所有文本拼接起來。在通過innerText寫入值時,結果會刪除元素的所有子節點,插入包含相應文本值的文本節點

<p id="test">This is a <i>simple</i> document</p>
<script>
console.log(test.innerText);//'This is a simple document'
test.innerText = '<div id="test"></div>';
console.log(test.innerText);//'<div id="test"></div>'
//即使在innerText中設置元素節點,最終也只是作為字符串內部的文本顯示
console.log(test.childNodes[0].nodeType);//3
</script>

  因此,設置innerText屬性只會生成當前節點的一個子文本節點Text。因此,可以利用將innerText設置為等於innerText來去掉所有HTML標簽

<p id="test">This is a <i>simple</i> document</p>
<script>
console.log(test.innerHTML);//'This is a <i>simple</i> document'
test.innerText = test.innerText;
console.log(test.innerHTML);//'This is a simple document'
</script>

【兼容】

  在早期的firefox瀏覽器中不支持innerText屬性,有下列兼容代碼

if(!'innerText' in document.body){
    HTMLElement.prototype.__defineGetter__('innerText',function(){
        return this.textContent;
    });
    HTMLElement.prototype.__defineSetter__('innerText',function(s){
        return this.textContent = s;
    });    
}

 

outerText

  在讀取文本值時,outerText與innerText的結果完全一樣,但在寫模式下,outerText不只是替換調用它的元素的子節點,而是會替換整個元素

<p id="test">This is a <i>simple</i> document</p>
<script>
console.log(test.outerText);//'This is a simple document'
test.outerText = '123';
console.log(document.body.childNodes[0]);//'  123'
//報錯,因為<p>元素已經被替換為'123',不再存在了
console.log(test.outerText);
</script>

 

textContent

  textContent屬性與innerText屬性類似,該屬性可讀寫。在讀模式下,返回當前節點和它的所有后代節點的文本內容;在寫模式下,結果會刪除元素的所有子節點,插入包含相應文本值的文本節點

  [注意]IE8-瀏覽器不支持該屬性

<p id="test">This is a <i>simple</i> document</p>
<script>
console.log(test.textContent);//'This is a simple document'
test.textContent = '<div id="test"></div>';
console.log(test.textContent);//'<div id="test"></div>'
//即使在textContent中設置元素節點,最終也只是作為字符串內部的文本顯示
console.log(test.childNodes[0].nodeType);//3
</script>

  與innerText不同的是,textContent屬性不僅屬於元素節點ElementNode,而是屬於所有節點Node

<p id="test">This is a <i>simple</i> document</p>
<script>
var oText = test.childNodes[0];
console.log(oText.textContent);//'This is a '
console.log(oText.innerText);//undefined
</script>

 

最后

  在firefox以前的版本中不支持innerText和outerText,但是隨着firefox的更新換代,這兩個屬性也開始支持。所以,上面的5個屬性的兼容問題都來源於IE8-瀏覽器。IE8-瀏覽器不支持textContent屬性,IE8-瀏覽器在使用innerHTML和outerHTML屬性時,會將所有標簽轉換成大寫形式,且不包含空白文本節點

  上面5個屬性中,常用的是innerHTML、outerHTML和innerText這3個


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM