jQuery被開發者如此的青睞和它強大的選擇器有很大關系,比起笨重的document.getElementById、document.getElementByName… ,查找元素很方便,其實W3C中提供了querySelector和querySelectorAll查詢接口已經實現了類似功能。
定義
其實這兩個方法看名字就能明白什么意思,不過還是引用一下W3C的解釋
querySelector:return the first matching Element node within the node’s subtrees. If there is no such node, the method must return null .(返回指定元素節點的子樹中匹配選擇器的集合中的第一個元素,如果沒有匹配返回null)
querySelectorAll:return a NodeList containing all of the matching Element nodes within the node’s subtrees, in document order. If there are no such nodes, the method must return an empty NodeList. (按文檔順序返回指定元素節點的子樹中匹配選擇器的元素集合,如果沒有匹配返回空集合)
從定義可以看到Document和Element都實現了NodeSelector接口。即這三種類型的元素都擁有者兩個方法。querySelector和querySelectorAll的參數是CSS選擇器字符串。區別在於querySelector返回的是一個第一個匹配元素,querySelectorAll返回的一個所有匹配元素集合(NodeList)。
用法
如果使用過jQuery或者了解CSS,這兩個方法使用很簡單,傳入選擇器即可
<div id="test"> <div class="dialog"> <p> 123</p> <span>456</span> <div> 789</div> <div class="text"> 452</div> </div> </div>
var test=document.querySelector('#test'); var subDivs = test.querySelectorAll('div'); var text = document.querySelectorAll('div[class=text]');
缺陷及解決辦法
確實很好用,但是瀏覽器對Element.querySelector和Element.querySelectorAll的實現有錯誤,看個例子
<div id="test"> <p> <span>123</span> </p> </div>
var test=document.querySelector('#test'); var span = test.querySelectorAll('div span');
按照我們的理解span因該是搜索test內部祖先元素為div的span元素,但是其祖先必須在test內部,而不能包括test本身甚至test的父元素,所以應該返回空基赫才對,但是瀏覽器會返回
大神Andrew Dupont提出了一種方法修復這個bug,被廣泛應用到各個框架中,在selector前面指定調用元素的id,限制匹配范圍。在jQuery中大概是這么個意思
var span, selector = 'div span',context=document.querySelector('#test'); var oldContext = context, oldId = context.getAttribute('id'), newId = oldId || '__sizzle__'; try { span= context.querySelectorAll('#'+newId+' '+selector); } catch (e) { } finally { if (!oldId) { oldContext.removeAttribute('id'); } }
這樣做其實是給搜索加了一層id的限制,巧妙的利用了這個bug,得到正確結果
瀏覽器兼容性
雖然有些問題,但瑕不掩瑜,這么好用的兩個方法咋沒火呢?瀏覽器兼容性。。。其實比起一些HTML5和CSS3的特性來說這兩個方法還沒那么讓人絕望,因為IE8都已經支持了,其它各個主力主流瀏覽器自然是實現了。
IE8+
Firefox
Chrome
Safari
Opera
Android
所以騷年們如果你是針對Mobile web優化,不要引用jQuery了,直接使用這兩個方法吧