1. 程式人生 > >深入理解javascript選擇器API系列第三篇——HTML5新增的3種selector方法

深入理解javascript選擇器API系列第三篇——HTML5新增的3種selector方法

前面的話

  儘管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

      ie8-不支援

複製程式碼
<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系列寫完了,歡迎交流