博客地址:https://ainyi.com/89
獲取 DOM 元素的幾種方式
get 方式:
- getElementById
- getElementsByTagName
- getElementsByClassName
- getElementsByName
返回類型 HTMLCollection[]
query 方式:
- querySelector
- querySelectorAll
返回類型 NodeList[]
獲取 dom 元素的詳細介紹:https://ainyi.com/31
獲取元素
首先用兩種方式獲取元素
let a = document.getElementsByClassName('title')
let b = document.querySelectorAll('.title')
一般循環
get 方式
get 方式獲取的 dom 元素,僅可使用for-in、for-of、for循環
for(let key in a) {
console.log(a[key])
}
// dom
// ...(每個dom元素)
// length(集合長度)
// ƒ item() { [native code] }
// ƒ namedItem() { [native code] }
其中:
ƒ item() { [native code] }
可通過 a.item(index) 獲取 dom 元素,類似 a[index]
ƒ namedItem() { [native code] }
可通過 a.namedItem('popo') 獲取 name 屬性為 'popo' 的 dom 元素(若多個元素有相同的 name 屬性,返回第一個)
for-of、for 循環可獲取每個 dom 元素:
for(let val of a) {
console.log(val)
}
// dom
// ...(每個dom元素)
for(let i = 0; i < a.length; i++) {
console.log(a[i])
}
// dom
// ...(每個dom元素)
query 方式
query 方式獲取的 dom 元素,可使用forEach、for-in、for-of、for循環
forEach、for-of、for 循環的結果無差別
但 for-in 相比 get 方式 的 for-in,循環得出的結果稍有不同
for(let key in b) {
console.log(b[key])
}
// dom
// ...(每個dom元素)
// length(集合長度)
// ƒ item() { [native code] }
// ƒ entries() { [native code] }
// ƒ forEach() { [native code] }
// ƒ keys() { [native code] }
// ƒ values() { [native code] }
與 get 方式的 for-in 相比,少了 ƒ namedItem() { [native code] },多了 Object 的幾個方法
這說明,query 方式獲取的 dom 元素集合,可執行 Object 對應的方法,但沒有 namedItem() 方法
ES6 轉換普通數組
ES6 提供了 Array.from() 方法可將這些集合轉換成普通數組,這樣就可以享用數組的各種方法了
let array = Array.from(a)
深度遍歷
節點樹的幾個屬性
- childElementCount:返回子元素(不包括文本節點和注釋)的數量
- parentNode:ele 的父節點
- childNodes:ele 的所有的直接子節點
- nextSibling:ele 的下一個同輩節點
- previousSibling:ele 的上一個同輩節點
因為 childNodes 包含看不見的空格文本,還有注釋等內容,所以使用起來不是太方便
因此,js 又重新引入了元素樹的概念。這個在我們實際應用中,用的比較普遍
元素樹:僅僅包含元素節點的樹結構,不是一顆新樹,盡是節點數的子集
為元素新增了下面幾個屬性:
- parentElement:節點的父元素
- children:返回節點的所有子元素
- firstElementChild:第一個直接子元素
- lastElementChild:最后一個直接子元素
- previousElementSibling:ele 的前一個兄弟元素
- nextElementSibling:ele 的下個兄弟元素
一般來說,區別元素節點,屬性節點,文本節點的通用方式是判斷該節點的 nodeType
常見的幾種 nodeType:
元素節點:1,
屬性節點:2,
文本節點:3,
注釋節點:8,
...
遍歷直接子級元素
假設 html 如下,要遍歷出 div 中的所有直接子級的元素節點:
<div id="list">
<p>hello</p>
<span>world</span>
<em>cookieParse()</em>
</div>
用 firstChild,lastChild 進行元素遍歷
let list = document.getElementById('list')
let child = list.firstChild
console.log(list.nextSibling)
while(child != list.lastChild) {
if(child.nodeType === 1) {
console.log( child )
}
child = child.nextSibling
}
使用 firstElementChild,nextElementSibling
let list = document.getElementById('list')
let child = list.firstElementChild
while(child) {
console.log( child )
child = child.nextElementSibling
}
深度優先遍歷
遍歷所有節點
深度優先遍歷:當同時有兄弟節點和子節點的時候,總是優先遍歷子節點
function getChildren(parent) {
// 如果當前節點是元素節點,輸出當前元素
parent.nodeType === 1 && console.log(parent);
// 獲得父節點的所有直接子節點
let children = parent.childNodes
// 遍歷 children 中每個節點
for(let i = 0, len = children.length; i<len; i++) {
// 對當前子節點遞歸
getChildren(children[i])
}
}
getChildren(document.body)
需要注意的是:遞歸的運行效率沒有迭代的運行效率高,一般都需要把遞歸的循環優化成迭代的循環
所以上面遞歸算法可以進一步優化
優化深度優先遍歷
使用 NodeIterator 對象,可以對 DOM 樹進行深度優先的搜索
創建 NodeIterator 對象,需要使用 document 對象的 createNodeIterator 方法,該方法接收四個參數:
- root:搜索開始的節點
- whatToShow:一個數值代碼,表示哪些節點需要搜索
- filter:NodeFilter 對象,決定忽略哪些節點
- entityReferenceExpansion:布爾值,表示是否需要擴展實體引用
whatToShow 參數:
參數 | 意義 |
---|---|
NodeFilter.SHOW_ALL | 顯示所有類型的節點 |
NodeFilter.SHOW_ELEMENT | 顯示元素節點 |
NodeFilter.SHOW_ATTRIBUTE | 顯示特性節點 |
NodeFilter.SHOW_TEXT | 顯示文本節點 |
NodeFilter.SHOW_CDATA_SECTION | 顯示CDATA節點。對HTML頁面無用 |
NodeFilter.SHOW_ENTITY_REFERENCE | 顯示實體引用節點 |
NodeFilter.SHOW_ENTITYE | 顯示實體節點 |
NodeFilter.SHOW_PROCESSING_INSTRUCTION | 顯示處理指令節點 |
NodeFilter.SHOW_COMMENT | 顯示注釋節點 |
NodeFilter.SHOW_DOCUMENT | 顯示元檔節點 |
NodeFilter.SHOW_DOCUMENT_TYPE | 顯示文檔類型節點 |
NodeFilter.SHOW_DOCUMENT_FRAGMENT | 顯示文檔片段節點 |
NodeFilter.SHOW_SHOW_NOTATION | 顯示符號節點 |
NodeFilter.SHOW_DOCUMENT_TYPE | 顯示文檔類型節點 |
優化如下:
function getChildren(parent){
// 獲取 NodeIterator 對象
let t = document.createNodeIterator(parent, NodeFilter.SHOW_ELEMENT, null, false)
// 循環遍歷對象的下一個節點
let currNode = null
while((currNode = t.nextNode()) !== null) {
// 節點不為空,就一直循環遍歷下去;直到為 null,才中斷循環
console.log(currNode)
}
}
getChildren(document.body)
博客地址:https://ainyi.com/89