JS中的動態合集與靜態合集


JS的動態合集

前言

DOM是JavaScript重要組成部分,在DOM中有三個特別的集合分別是NodeList(節點的集合),NamedNodeMap(元素屬性的集合)和HTMLCollection(html元素的集合)。這三個集合有一些共同的特點:它們都是一個類數組對象,可以通過中括號表達式來訪問集合中元素,也有length屬性。但它們並不是數組,而且它們都是動態的(querySelectorAll()返回的NodeList除外),會根據頁面元素的變化而變化。下面就來介紹一下它們。

NodeList集合

如何獲取NodeList集合

DOM將HTML頁面解析成一個由多層次節點構成的結構。節點是頁面結構的基礎,而所有節點繼承自Node類型,因此所有節點共享着基本的屬性和方法。Node類型有一個childNodes屬性,所以所有節點都擁有這個屬性。而通過這個屬性就可以得到一個保存着本節點的子節點組成的NodeList對象。

如何操作NodeList

NodeList可以通過方括號表達式來訪問,也可以通過item()方法來訪問,也有length屬性,可以訪問元素個數。 雖然javascript中的數組可以修改length屬性。但NodeList集合並不是數組,而且它是頁面一片區域的DOM結構映射。所以請不要修改NodeList對象的length值。

var firstChild = someNode.childNodes[0];//獲取第一個元素
var secondChild = someNode.childNodes.item(1);//獲取第二個元素
var count = someNode.childNodes.length;//獲取集合長度

NamedNodeMap

如何獲取NamedNodeMap

Element類型這種DOM節點是唯一擁有attributes屬性的一種節點類型。而attribute屬性中就包含NamedNodeMap集合。它由元素的特性組成。所以只要是元素節點,調用attributes屬性就可以得到NamedNodeMap集合。

如何操作NamedNodeMap集合

可能一些人沒有聽過NamedNodeMap對象,該對象的常見實例對象是attributes屬性

<div id="test"></div>
<script>
    var attrs = test.attributes;
    console.log(attrs instanceof NamedNodeMap); //true
</script>

NamedNodeMap集合的元素擁有nodeName和nodeValue屬性,分別表示元素特性名稱和特性值,也擁有以下方法:

  • getNamedItem(name);返回nodeName屬性等於name的節點;
  • removeNamedItem(name);從列表中移除nodeName節點;
  • setNamedItem(node);向列表中添加節點,以節點nodeName為屬性索引;
  • item(pos);返回位於數字pos位置的節點。
var className = element.attributes.getNamedItem('class').nodeValue;
var className1 = element.attributes['class'].nodeValue;
var oldAttr = element.attributes.removeNamedItem('class');

一般元素節點的getAttribute()、removeAttribute()和setAttribute()方法都可以完成以上操作

HTMLCollection

如何得到HTMLCollection集合

HTMLCollection是元素節點的集合可以通過getElementsByTagName()方法(獲取同類型的元素)、getElementsByClassName()(獲取class特性相同的元素)、getElementsByName()方法(獲取name特性相同的元素)、document的anchors屬性(包含name特性的a元素),forms屬性(包含文檔所有form元素),images屬性(包含文檔所有img元素),links屬性(文檔所有帶href特性的a元素)。

與NodeList區別

NodeList集合主要是Node節點的集合,而HTMLCollection集合主要是Element元素節點的集合。Node節點共有12種,Element元素節點只是其中一種。

注意事項

這三個集合都是“動態的”;當文檔結構發生變化時,它們都會更新,所以以下操作就會發生錯誤:

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
    var div = document.createElement('div');
    document.body.appendChild(div);
}

以上代碼中的for循環將會一直執行,因為div得到的HTMLCollection集合是動態的,當每次給body添加元素divs都會進行更新,所以會一直循環下去。

解決方法1:將初始的集合的length存起來

var divs = document.getElementsByTagName('div');
for (var i = 0, var len = divs.length; i < len; i++) {
    var div = document.createElement('div');
    document.body.appendChild(div);
}

解決方法2:將以上集合轉化為數組

var divs = document.getElementsByTagName('div');
//將HTMLCollection轉換為數組(此方法在IE8及以前不能用)
var divsArr = Array.prototype.slice.call(divs,0);
for (var i = 0; i < divsArr.length; i++) {
    var div = document.createElement('div');
    document.body.appendChild(div);
}

由於IE8-瀏覽器將NodeList實現為一個COM對象,不能使用Array.prototype.slice()方法,必須手動枚舉所有成員

將以上集合轉為數組的方法(通用):

function convertListToArray(nodes) {
   var array = null;
   try{//標准瀏覽器
       array = Array.prototype.slice.call(nodes,0);
   }catch(ex){//IE8及以下遍歷每一項分別添加到數組中
       array = new Array();
       for(var i = 0,len = nodes.length;i < len;i++){
           array.push(nodes[i]);
       }
   }
   return array;
}

JS的靜態合集

前言

除了getElementsByClassName()方法外,HTML5中DOM拓展了querySelectorAll()、querySelector()和matchesSelector()這3種方法,通過CSS選擇符查詢DOM文檔取得元素的引用的功能變成了原生的API,解析和樹查詢操作在瀏覽器內部通過編譯后的代碼來完成,極大地改善了性能。

與getElementById()方法不同,querySelector()方法得到的對象是靜態對象

與getElementsByTagName()等方法不同,querySelectorAll()方法得到的類數組對象是靜態合集。

querySelector()

querySelector()方法接收一個CSS選擇符,返回與該模式匹配的第一個元素,如果沒有找到匹配的元素,返回null。該方法既可用於文檔document類型,也可用於元素element類型。

<body style="height: 100%;">
<div class="box" id="box" style="height: 200px;">
<ul class="list" style="height:100px">
        <li class="in" style="height: 30px;">1</li>
        <li class="in" style="height: 30px;" title="test">2</li>
        <li class="in" style="height: 30px;">3</li>
    </ul>    
</div>
<script>
    //因為沒有.null類名,所以返回null
    var oNull = document.querySelector('.null');
    console.log(oNull); //null
    //通過<body>標簽取得元素
    var body = document.querySelector("body");
    console.log(body.style.height); //100%
    //通過id屬性取得元素
    var oBox = document.querySelector('#box');
    console.log(oBox.style.height); //200px
    //通過結合元素的類選擇器取得元素
    var oList = document.querySelector('ul.list');
    console.log(oList.style.height); //100px
    //通過類名取得元素
    var oIn = document.querySelector('.in');
    console.log(oIn.innerHTML); //1
    //通過屬性選擇器取得元素
    var oTest = body.querySelector('[title="test"]');
    console.log(oTest.innerHTML); //2
</script>
</body> 

querySelectorAll()

querySelectorAll()接收一個CSS選擇符,返回一個類數組對象NodeList的實例。具體來說,返回的值實際上是帶有所有屬性和方法的NodeList,而其底層實現則類似於一組元素的快照,而非不斷對文檔進行搜索的動態查詢。這樣實現可以避免使用NodeList對象通常會引起的大多數性能問題。

沒有匹配元素時,返回空的類數組對象,而不是null

<body style="height: 100%;">
<div class="box" id="box" style="height: 200px;">
<ul class="list" style="height:100px">
        <li class="in" style="height: 30px;">1</li>
        <li class="in" style="height: 30px;" title="test">2</li>
        <li class="in" style="height: 30px;">3</li>
    </ul>    
</div>
<script>
    //返回[]
    var oNull = document.querySelectorAll('.null');
    console.log(oNull);
    //取得body元素
    var body = document.querySelectorAll("body")[0];
    console.log(body.style.height); //100%
    //取得所有class為"in"的元素
    var oIn = document.querySelectorAll('.in');
    for (var i = 0; i < oIn.length; i++) {
        console.log(oIn[i].innerHTML); //1,2,3    
    }
    //取得title屬性為test的元素
    var oTest = body.querySelectorAll('[title="test"]');
    console.log(oTest); //[li.in]
</script>
</body>

缺陷

selector類方法在元素上調用時,指定的選擇器仍然在整個文檔中進行匹配,然后過濾出結果集,以便它只包含指定元素的后代元素。它意味着選擇器字符串能包含元素的祖先而不僅僅是所匹配的元素

<div id="container">
    <div>1</div>
    <div>2</div>
</div>
<script>
    var container = document.getElementById('container');
    console.log(container.querySelectorAll('div div')); //[div div]
</script>

所以,如果出現后代選擇器,為了防止該問題,可以在參數中顯式地添加當前元素的選擇器

<div id="container">
    <div>1</div>
    <div>2</div>
</div>
<script>
    var container = document.getElementById('container');
    console.log(container.querySelectorAll('#container div div')); //[]
    console.log(container.querySelectorAll('#container div')); //[div div]
    console.log(container.querySelectorAll('div')); //[div div]
</script>


免責聲明!

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



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