每個網頁都是一個dom樹,網頁中所有的內容都是這個樹上的一個節點。JavaScript的工作就是操作這些節點,對節點進行查增刪改操作,或是給節點綁定事件。
網頁
dom樹
要操作dom節點,首先要獲取到dom節點。這里我介紹幾個原生js獲取元素子節點的方法:
一、通過標簽的屬性值獲取后代節點
以getElementBy開頭的方法,可以根據具體的屬性獲取元素的后代節點。這些方法不只會獲取子節點,他也會獲取到所有符合條件的后代節點。
方法 | 依據屬性 | 兼容性 | 其他 |
getElementById | id | 兼容性好,推薦使用 |
如果存在多個id相同的元素,只會返回第一個 |
getElementsByTagName | 標簽名 | 不兼容ie8及以下版本 | 返回所有符合條件的元素的集合 |
getElementsByName | name | 不兼容ie8及以下版本 | 返回所有符合條件的元素的集合 |
getElementsByClassName | class | 不兼容ie8及以下版本 | 返回所有符合條件的元素的集合 |
以getElementById為例,盡管有兩個id為’Jan‘的元素,但是只會獲取到第一個:
<html> <head> </head> <body> <p id='Jan' class='test'>1</p> <p id='Jan' class='test'>2</p> <p id='Mar'>3</p> </body> <script type="text/javascript"> var j=document.getElementById('Jan'); console.log(j); </script> </html>
需要注意的是,在同一個文件中出現重復id是不符合規范的,應當盡量避免這樣使用。
如果將上面代碼中的getElementById('Jan')換成 getElementsByTagName('p')或者是getElementsByClassName('test')將會獲取到符合條件的結果集。
二、child屬性
每個dom元素都是一個對象,在dom元素對象中有四個專門用於獲取子元素的屬性:
屬性名 | 作用 | 其他 |
childNodes | 獲取所有子節點 | 不推薦使用,如果有空格,會作為文本節點獲取到 |
child | 獲取所有子節點 | 推薦使用 |
firstChild | 獲取首個子節點 | 推薦使用 |
lastChild | 獲取最后一個子節點 | 推薦使用 |
這四個屬性都不存在兼容性問題,除了childNodes之外都是比較好用的。
1. childNodes
childNodes屬性可以獲取元素的所有子節點,並封裝到一個數組中,可以通過下標來獲取某個子元素:
<html> <head> </head> <body> <div class="test" id="test"> <p>1</p> <p>3</p> <p>5</p> </div> </body> <script> var a = document.getElementById("test"); console.log(a.childNodes); </script> </html>
但是childNodes屬性有一個問題,class=‘test’的div中只有3子節點,執行結果卻有7個節點:
因為根據在網頁中,標簽之間的回車空格等特殊字符屬於一個p元素,上面的div中輸入了4個回車,因此會多出四個text節點:
要解決這個問題有兩個方法:
方法一:去掉所有的回車空格等特殊字符,但是會影響程序的可讀性和代碼的規范。
方法二:動態過濾掉空白字符:
通過for循環遍歷對象中的所有元素,刪除純文本元素。
完整的代碼就是這樣:
var a = document.getElementById("test"); var b = a.childNodes; for(i=0;i<b.length;i++){ if(b[i].nodeName == "#text"&& !/\s/.test(b.nodeValue)){ a.removeChild(b[i]); } }
第二種方法每次查詢之前,都要先執行一段過濾代碼。這樣會影響程序的執行效率,因此childNodes屬性不建議使用。
2. children
相比childNodes,children屬性不會將空格作為文本節點獲取。因此就不需要額外的去除空格操作,獲取節點的方式和chlidNodes屬性相同。
還是用上面的代碼,將 a.childNodes 修改為 a.child 之后,會獲取到三個p元素,這就是通常希望得到的結果。
chilren和childNodes屬性存在的缺點是會獲取全部的子節點,某些情況下使用時需要篩選,不夠靈活。
3. firstChild&lastChild
firstChild會獲取首個子節點,相當於children[0]的效果。
lastChild會獲取最后一個子節點,相當於children[children.length-1]
三、querySelector方法,強烈推薦!
querySelector的參數是css選擇器,任何選擇器都可以作為它的參數,這樣就使得它非常方便靈活:
比如獲取class=‘test’的標簽下的第一個子元素,可以這樣寫querySelector('.test > * '),也可以指定子元素的類型querySelector('.test > span '),或者是:classquerySelector('.test > #f_div')
還可以使用querySelectorAll方法,這樣會獲取所有滿足條件的元素,而不只是獲取第一個元素。
<div class="first"> <span>張三</span> </div> <div id="second"> <div id=f_div></div> <div></div> <div></div> <div></div> <div></div> </div> <script> //通過類選擇器獲取節點 doucument.querySelector('.first'); //通過id選擇器獲取節點 doucument.querySelector('#second'); //通過偽類選擇器獲取子節點 document.querySelector('.first>span'); //確認selectAll批量獲取節點 document.querySelectorAll('#second>div'); </script>
總體來說,我比較推薦使用querySelector方法,因為它更加靈活,使用作為css選擇器進行選擇非常方便。當然querySelector方法不只可以獲取元素的子節點,它可以獲取任何節點。querySelector方法可以兼容到IE8,基本能滿足前端開發兼容性的需要。