按照標簽名獲取元素 -- getElementsByTagName
標准
- DOM 1在
Element
和Document
兩個interface中均有定義,原型NodeList getElementsByTagName(in DOMString tagname)
,指明按照先序遍歷遇到的順序排列,不會拋出任何異常,參數"*"
返回對應document或者element下所有元素。注意這里指明返回的是一個live的僅含有Element
的NodeList
。 - DOM 2里定義仍在
Element
和Document
,增加了帶namespace的NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName)
(Element
,Document
),引入了localName
的概念(只有ELEMENT_NODE
和ATTRIBUTE_NODE
才能有)。 - DOM 3(
Document
,Element
)特別聲明XML應當對標簽名的大小寫敏感,非XML則依照文檔類型自己對待大小寫的風格來決定是否敏感。實際上瀏覽器對HTML都會先將標簽轉統一換成成小寫后再去匹配,所以只能匹配到實際標簽名為小寫的元素。 - WHATWG (
Document
,Element
)將返回類型修改為了HTMLCollection
,並解釋了通過localName
產生HTMLCollection
的算法。注意算法的第二步實際上規定了在非HTML文檔里,標簽名大小寫敏感;而在HTML文檔里,任何大小寫的標簽都會被統一轉換成小寫后再去匹配,所以只能匹配到實際標簽名為小寫的元素。 - DOM 4(Document,Element) 目前與 WHATWG 基本一致
DOM Tree Accessors
DOM 1 與 DOM 2 的 HTMLDocument
interface 里定義了一系列"DOM Tree Accessors"
readonly attribute HTMLCollection images
readonly attribute HTMLCollection applets
readonly attribute HTMLCollection links
readonly attribute HTMLCollection forms
readonly attribute HTMLCollection anchors
attribute HTMLElement body
這意味着在HTML文檔里可以用document.images
獲得所有<img>
元素,用document.links
獲取所有帶有href
屬性的<a>
元素,用document.links
獲取所有帶有name
屬性的<a>
元素,用document.forms
獲取所有<form>
元素。另外獲取<body>
可以使用document.body
。
自 HTML5(W3C,WHATWG)開始還定義了document.head
,刪去了document.anchors
,增加了獲取<embed>
的document.embeds
和目前與之相同的document.plugins
,以及獲取<script>
的document.scripts
。
自 DOM 1 便在Document
定義了document.documentElement
來獲取根元素並保留至今,在HTML文檔里即<html>
元素。
兼容性
- IE 5.5 不支持
*
作為參數獲取所有元素。IE6以上的IE以及各大瀏覽器均按照標准實現了getElementsByTagName
。 - 雖然
document.scripts
,document.embeds
和document.plugins
直到HTML5才標准化,不過各版本IE和其他瀏覽器的現行版本都支持 document.head
需要IE9+才支持。其他DOM Tree Accessor基本在各版本IE和現行的瀏覽器里都有支持。
Webkit 代碼分析
類似getElementsByName
,getElementsByTagName
在ContainerNode
里實現。由於標准里對XML的特殊規定,這里會依據文檔類型,換用TagNodeList
或者HTMLTagNodeList
作為NodeListsNodeData::addCacheWithAtomicName<>
的template specialization(參見WebCore/dom/ContainerNode.cpp)。
TagNodeList
實現的elementMatches
是:
if (m_localName != starAtom && m_localName != element.localName()) return false; return m_namespaceURI == starAtom || m_namespaceURI == element.namespaceURI();
這里starAtom
就是標准里說的*
。先比對localName是否相符或為*
,然后比對namespaceURI是否相符或為*
。由於沒有大小寫轉換步驟,所以遵循標准,是大小寫敏感的。注意這里比對namespaceURI的步驟相對於getElementsByTagName
是多余的,之所以加上是因為getElementsByTagNameNS
也用TagNodeList
,這樣就可以偷懶不用再多寫一個比對namespaceURI的版本。不過getElementsByTagNameNS
用的其實是addCacheWithQualifiedName
而不是addCacheWithAtomicName
,其實addCacheWithQualifiedName
和addCacheWithAtomicName
的不同也就是它拿TagNodeList
直接提前做好了template specification而已(參見WebCore/dom/NodeRareData.h)
HTMLTagNodeList
實現的elementMatches
是:
if (m_localName == starAtom) return true; const AtomicString& localName = element.isHTMLElement() ? m_loweredLocalName : m_localName; return localName == element.localName();
按照標准所說,如果被比對的元素是HTML namespace里的,轉換為小寫再比較。注意這里沒有比對namespaceURI,畢竟getElementsByTagNameNS
不用它(標准里沒有指明getElementsByTagNameNS
需要轉換大小寫,所以用TagNodeList
那個大小寫敏感的過濾足矣)。