本篇文章以介紹常見的DOM節點知識、DOM元素操做方法爲目的,其中也對一些比較容易忽略的問題進行簡要說明。才疏學淺,若有紕漏之處或建議歡迎留下評論。css
首先,簡單看看Node節點。有三個屬性我的認爲比較須要注意,nodeType、nodeName、nodeValue。html
這個圖是來自《Javascript高級程序設計》一書中的Node節點間的關係圖譜,比較清晰地介紹了節點之間的關係。node
特別注意上述屬性獲取的並不僅是元素節點,也會包含文本節點等。因此進行操做時須要進行元素類型判斷過濾。
此外,還有一些方式能夠得到相關的元素節點。數組
方法 | 簡述 | 兼容性 |
---|---|---|
getElementById('id') | 經過id獲取 | - |
getElementsByTagName('p') | 經過標籤名獲取 | - |
getElementsByClassName('class') | 經過class獲取 | IE>= 9 |
getElementsByName('name') | 經過name屬性獲取 | - |
querySelector() | 返回匹配選擇器的第一個元素 | IE >= 8 |
querySelectorAll() | 返回匹配選擇器的全部元素 | IE >=8 |
特別注意:querySelectorAll()與其餘方法獲取的DOM元素是不一樣的,它返回的是靜態的
NodeList 對象,其餘返回的是動態的 HTMLCollection 對象。靜態意味着不會隨着DOM結構的變換而改變。舉例以下:瀏覽器
// html <ul id="list"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> </ul> //js let list = document.getElementById('list'), child1 = document.getElementsByTagName('li'), child2 = document.querySelectorAll('li') console.log(child1.length) // 6 console.log(child2.length) // 6 let ele = document.createElement('li') ele.innerHTML = 7 list.appendChild(ele) console.log(child1.length) // 7 console.log(child2.length) // 6
因此,在使用getElementsByTagName、getElementsByClassName、getElementsByName方法時要特別注意循環處理DOM節點的狀況。app
createElement() 建立一個元素節點
createTextNode() 建立一個文本節點
createAttribute() 建立一個屬性節點(用setAttribute方法更加方便)
createDocumentFragment() 建立一個文檔片斷(適合在批量操做DOM元素時使用,詳見後面章節的例子)wordpress
元素內容的獲取
這裏有幾個容易混淆的屬性,innerHTML、outerHTML、innerText、outerText、textContent,都是能夠獲取元素內容。區別以下:性能
屬性 | 描述 | 兼容性 |
---|---|---|
innerHTML | 返回HTML文本,存在XSS攻擊的問題。 | |
outerHTML | 返回內容包含元素及其後代的HTML文本。 | |
textContent | 返回元素全部文本內容,包括隱藏元素的文本,包括<style>、<script>不會返回HTML文本,避免直接設置HTML文本。 | IE9+ |
innerText | 返回文本內容,受CSS樣式影響,會觸發DOM重排,不包括隱藏元素的文本,不包括<style>、<script>,避免直接設置HTML文本。 | |
outerText | 非標準屬性。獲取時返回與innerText相同內容,設置時刪除當前節點替換爲給定文本。 |
元素屬性
Element.attributes(): 引用MDN官網的描述spa
返回該元素全部屬性節點的一個實時集合。該集合是一個 NamedNodeMap 對象,不是一個數組,因此它沒有數組的方法,其包含的屬性節點的索引順序隨瀏覽器不一樣而不一樣。更確切地說,attributes 是字符串形式的名(name)/值(value)對,每一對名/值對對應一個屬性節點。設計
ele.getAttribute(attributeName) 獲取屬性
ele.setAttribute(name, value) 設置屬性
HTMLElement.dataset: 獲取data-*屬性集
元素樣式
HTMLElement.style 返回元素的內聯樣式(沒錯,樣式表的屬性會被忽略)
單個樣式的設置:ele.style.color='#000'
多個樣式的設置:
ele.style.cssText='color: blue'
ele.setAttribute('style', 'color: blue')
獲取元素樣式信息:
window.getComputedStyle(ele).color
window.getComputedStyle(ele).getPropertyValue('color')
'::after'
。關於getComputedStyle詳細介紹能夠看看張鑫旭大神的獲取元素CSS值之getComputedStyle方法一文。方法 | 簡述 |
---|---|
node.appendChild(newNode) | 向node節點插入一個新節點newNode |
node.insertBefore(newNode, tarNode) | 在node節點的tarNode子節點前插入一個新節點newNode |
node.replaceChild(newNode, tarNode) | 替換node節點的tarNode子節點爲新節點newNode |
node.removeChild(tarNode) | 移除node節點的tarNode子節點 |
node.cloneNode(flag) | 複製節點,flag: true 深複製;flag: false 淺複製 |
此處深複製爲複製節點及其整個子樹,淺複製則僅複製節點自己。
頻繁進行DOM操做其實會形成屢次重排Reflow,影響性能。舉個常見的例子,在id爲container的元素中添加5個按鈕,每一個按鈕的文案是相應序號,點擊打印輸出對應序號。解決辦法有如下幾種:
依次建立button元素,使用appenChild添加到列表中
固然,這個方法是最不推薦的,由於屢次對DOM進行操做,會形成屢次頁面重排,性能太差。
let container = document.getElementById('container') for(let i = 1; i <= 5; i++) { let btn = document.createElement('button'), text = document.createTextNode(i) btn.appendChild(text) btn.addEventListener('click', () => { console.log(i) }) container.appendChild(btn) }
利用DocumentFragment
引用MDN官網關於DocumentFragment的介紹:
DocumentFragment 接口表示一個沒有父級文件的最小文檔對象。它被當作一個輕量版本的 Document 使用,用於存儲已排好版的或還沒有打理好格式的XML片斷。最大的區別是由於DocumentFragment不是真實DOM樹的其中一部分,它的變化不會引發DOM樹的從新渲染的操做(reflow) ,或者致使性能影響的問題出現。
沒錯,利用DocumentFragment咱們可以避免方法1中屢次操做DOM的問題,性能獲得提高。
let container = document.getElementById('container'), fragment = document.createDocumentFragment() for(let i = 1; i <= 5; i++) { let btn = document.createElement('button'), text = document.createTextNode(i) btn.appendChild(text) btn.addEventListener('click', () => { console.log(i) }) fragment.appendChild(btn) } container.appendChild(fragment)
利用字符串拼接
使用字符串拼接的方法插入DOM元素是效率最高的。而且,這裏將事件綁定到了父元素上,一方面可使用動態添加元素的事件,另外一方面當須要在大量元素上綁定事件時,這種方法更加優雅而且節省內存。
let container = document.getElementById('container'), btns = ''; for(let i = 1; i <= 5; i++) { let btn = `<button class="btn_num">${i}</button>` btns += btn } container.addEventListener('click', (event) => { let target = event.target if(target.className == 'btn_num') { console.log(target.innerHTML) } }) container.innerHTML = btns