前面的話
盡管DOM作為API已經非常完善了,但是為了實現更多的功能,DOM仍然進行了擴展,其中一個重要的擴展就是對選擇器API的擴展。人們對jQuery的稱贊,很多是由于jQuery方便的元素選擇器。除了前面已經介紹過的getElementsByClassName()方法外,DOM拓展了querySelectorAll()、querySelector()和matchesSelector()這3種方法,通過CSS選擇符查詢DOM文檔取得元素的引用的功能變成了原生的API,解析和樹查詢操作在瀏覽器內部通過編譯后的代碼來完成,極大地改善了性能。本文將詳細介紹html5新增的3種selector方法
方法
querySelector()
querySelector()方法接收一個CSS選擇符,返回與該模式匹配的第一個元素,如果沒有找到匹配的元素,返回null。該方法既可用于文檔document類型,也可用于元素element類型。關于CSS選擇器的詳細內容移步至此
[注意]IE7-瀏覽器不支持
<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對象通常會引起的大多數性能問題。只要傳給querySelectorAll()方法的CSS選擇符有效,該方法都會返回一個NodeList對象,而不管找到多少匹配的元素
沒有匹配元素時,返回空的類數組對象,而不是null
[注意]IE7-瀏覽器不支持
<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>
matchesSelector()
matchesSelector()方法接收一個CSS選擇符參數,如果調用元素與該選擇符相匹配,返回true;否則返回false
<body id="test"> <script> //Uncaught TypeError: document.body.matchesSelector is not a function console.log(document.body.matchesSelector('#test')); </script> </body>
由于兼容性問題,現在各個瀏覽器都只支持加前綴的方法。IE9+瀏覽器支持msMatchesSelector()方法,firefox支持mozMatchesSelector()方法,safari和chrome支持webkitMatchesSelector()方法。所以兼容寫法為:
function matchesSelector(element,selector){
if(element.matchesSelector){
return element.matchesSelector(selector);
}
if(element.msMatchesSelector){
return element.msMatchesSelector(selector);
}
if(element.mozMatchesSelector){
return element.mozMatchesSelector(selector);
}
if(element.webkitMatchesSelector){
return element.webkitMatchesSelector(selector);
}
}
<body id="test"> <script> console.log(matchesSelector(document.body,'#test'));//true </script> </body>
非實時
與getElementById()和getElementsByTagName()方法不同,querySelector()和querySelectorAll()方法得到的類數組對象是非動態實時的
<div id="container"> <div>1</div> <div>2</div> </div> <script> var container = document.getElementById('container'); var divOne = container.querySelector('div:last-child'); var divAll = container.querySelectorAll('div'); console.log(container.children.length);//2 console.log(divOne.innerHTML);//2 console.log(divAll.length);//2 var newDiv = document.createElement('div'); newDiv.innerHTML = 3; container.appendChild(newDiv); console.log(container.children.length);//3 //由于querySelector不是實時的,所以其保存的仍然是原來第二個div的值 console.log(divOne.innerHTML);//2 //由于querySelectorAll不是實時的,所以仍然只保存了兩個div元素 console.log(divAll.length);//2 console.log(container.querySelector('div:last-child').innerHTML);//3 console.log(container.querySelectorAll('div').length);//3 </script>
缺陷
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>
按照正常理解,控制臺應該返回空的類數組對象,因為id為container的div元素的子元素中,不存在div元素嵌套的情況
但是,該方法實際返回[div div]。這是因為參數中的選擇器包含了元素的祖先
所以,如果出現后代選擇器,為了防止該問題,可以在參數中顯式地添加當前元素的選擇器
<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>
最后
雖然存在著非實時和參數缺陷的問題,但是瑕不掩瑜,selector類方法的出現極大地簡化了查找元素的繁瑣操作。而且,它們支持IE8瀏覽器
javascript選擇器API系列寫完了,歡迎交流
文章列表