JavaScript 操作 DOM 常用 API 總結
文字整理了javascript操作DOM的一些常用的api,根據其作用整理成為建立,修改,查詢等多種型別的api,主要用於複習基礎知識,加深對原生js的認識。
基本概念
在講解操作DOM的api之前,首先我們來複習一下一些基本概念,這些概念是掌握api的關鍵,必須理解它們。
Node型別
DOM1級定義了一個Node介面,該介面由DOM中所有節點型別實現。這個Node介面在JS中是作為Node型別實現的。在IE9以下版本無法訪問到這個型別,JS中所有節點都繼承自Node型別,都共享著相同的基本屬性和方法。
Node有一個屬性nodeType表示Node的型別,它是一個整數,其數值分別表示相應的Node型別,具體如下:
Node.ELEMENT_NODE:1
Node.ATTRIBUTE_NODE:2
Node.TEXT_NODE:3
Node.CDATA_SECTION_NODE:4
Node.ENTITY_REFERENCE_NODE:5
Node.ENTITY_NODE:6
Node.PROCESSING_INSTRUCTION_NODE:7
Node.COMMENT_NODE:8
Node.DOCUMENT_NODE:9
Node.DOCUMENT_TYPE_NODE:10
Node.DOCUMENT_FRAGMENT_NODE:11
Node.NOTATION_NODE:12
假設我們要判斷一個Node是不是元素,我們可以這樣判斷
if(someNode.nodeType == 1){ console.log("Node is a element"); }
這些Node型別中,我們最常用的就是element,text,attribute,comment,document,document_fragment這幾種型別。
我們簡單來介紹一下這幾種型別:
Element型別
Element提供了對元素標籤名,子節點和特性的訪問,我們常用HTML元素比如div,span,a等標籤就是element中的一種。Element有下面幾條特性:
(1)nodeType為1
(2)nodeName為元素標籤名,tagName也是返回標籤名
(3)nodeValue為null
(4)parentNode可能是Document或Element
(5)子節點可能是Element,Text,Comment,Processing_Instruction,CDATASection或EntityReference
Text型別
Text表示文字節點,它包含的是純文字內容,不能包含html程式碼,但可以包含轉義後的html程式碼。Text有下面的特性:
(1)nodeType為3
(2)nodeName為#text
(3)nodeValue為文字內容
(4)parentNode是一個Element
(5)沒有子節點
Attr型別
Attr型別表示元素的特性,相當於元素的attributes屬性中的節點,它有下面的特性:
(1)nodeType值為2
(2)nodeName是特性的名稱
(3)nodeValue是特性的值
(4)parentNode為null
Comment型別
Comment表示HTML文件中的註釋,它有下面的幾種特徵:
(1)nodeType為8
(2)nodeName為#comment
(3)nodeValue為註釋的內容
(4)parentNode可能是Document或Element
(5)沒有子節點
Document
Document表示文件,在瀏覽器中,document物件是HTMLDocument的一個例項,表示整個頁面,它同時也是window物件的一個屬性。Document有下面的特性:
(1)nodeType為9
(2)nodeName為#document
(3)nodeValue為null
(4)parentNode為null
(5)子節點可能是一個DocumentType或Element
DocumentFragment型別
DocumentFragment是所有節點中唯一一個沒有對應標記的型別,它表示一種輕量級的文件,可能當作一個臨時的倉庫用來儲存可能會新增到文件中的節點。DocumentFragment有下面的特性:
(1)nodeType為11
(2)nodeName為#document-fragment
(3)nodeValue為null
(4)parentNode為null
我們簡單地介紹了幾種常見的Node型別,要記住,HTML中的節點並不只是包括元素節點,它還包括文字節點,註釋節點等等。在這裡我們只是簡單地說明了幾種常見的節點,想要進一步學習的同學可以查詢一下相關資料。
節點建立型api
在這裡,我將常用的DOM操作api進行分類,首先要介紹的是建立型的api。這一型別的api,簡而言之就是用來建立節點的。
createElement
createElement通過傳入指定的一個標籤名來建立一個元素,如果傳入的標籤名是一個未知的,則會建立一個自定義的標籤,注意:IE8以下瀏覽器不支援自定義標籤。
使用如下:
var div = document.createElement("div");
使用createElement要注意:通過createElement建立的元素並不屬於html文件,它只是建立出來,並未新增到html文件中,要呼叫appendChild或insertBefore等方法將其新增到HTML文件樹中。
createTextNode
createTextNode用來建立一個文字節點,用法如下:
var textNode = document.createTextNode("一個TextNode");
createTextNode接收一個引數,這個引數就是文字節點中的文字,和createElement一樣,建立後的文字節點也只是獨立的一個節點,同樣需要appendChild將其新增到HTML文件樹中
cloneNode
cloneNode是用來返回撥用方法的節點的一個副本,它接收一個bool引數,用來表示是否複製子元素,使用如下:
var parent = document.getElementById("parentElement"); var parent2 = parent.cloneNode(true);// 傳入true parent2.id = "parent2";
這段程式碼通過cloneNode複製了一份parent元素,其中cloneNode的引數為true,表示parent的子節點也被複制,如果傳入false,則表示只複製了parent節點。
我們看看這個例子
<div id="parent"> 我是父元素的文字 <br/> <span> 我是子元素 </span> </div> <button id="btnCopy">複製</button> var parent = document.getElementById("parent"); document.getElementById("btnCopy").onclick = function(){ var parent2 = parent.cloneNode(true); parent2.id = "parent2"; document.body.appendChild(parent2); }
這段程式碼很簡單,主要是繫結button事件,事件內容是複製了一個parent,修改其id,然後新增到文件中。
這裡有幾點要注意:
(1)和createElement一樣,cloneNode建立的節點只是遊離有html文件外的節點,要呼叫appendChild方法才能新增到文件樹中
(2)如果複製的元素有id,則其副本同樣會包含該id,由於id具有唯一性,所以在複製節點後必須要修改其id
(3)呼叫接收的bool引數最好傳入,如果不傳入該引數,不同瀏覽器對其預設值的處理可能不同
除此之外,我們還有一個需要注意的點:
如果被複制的節點繫結了事件,則副本也會跟著繫結該事件嗎?這裡要分情況討論:
(1)如果是通過addEventListener或者比如onclick進行繫結事件,則副本節點不會繫結該事件
(2)如果是內聯方式繫結比如
<div onclick="showParent()"></div>
這樣的話,副本節點同樣會觸發事件。
createDocumentFragment
createDocumentFragment方法用來建立一個DocumentFragment。在前面我們說到DocumentFragment表示一種輕量級的文件,它的作用主要是儲存臨時的節點用來準備新增到文件中。
createDocumentFragment方法主要是用於新增大量節點到文件中時會使用到。假設要迴圈一組資料,然後建立多個節點新增到文件中,比如示例
<ul id="list"></ul> <input type="button" value="新增多項" id="btnAdd" /> document.getElementById("btnAdd").onclick = function(){ var list = document.getElementById("list"); for(var i = 0;i < 100; i++){ var li = document.createElement("li"); li.textContent = i; list.appendChild(li); } }
這段程式碼將按鈕繫結了一個事件,這個事件建立了100個li節點,然後依次將其新增HTML文件中。這樣做有一個缺點:每次一建立一個新的元素,然後新增到文件樹中,這個過程會造成瀏覽器的迴流。所謂迴流簡單說就是指元素大小和位置會被重新計算,如果新增的元素太多,會造成效能問題。這個時候,就是使用createDocumentFragment了。
DocumentFragment不是文件樹的一部分,它是儲存在記憶體中的,所以不會造成迴流問題。我們修改上面的程式碼如下:
document.getElementById("btnAdd").onclick = function(){ var list = document.getElementById("list"); var fragment = document.createDocumentFragment(); for(var i = 0;i < 100; i++){ var li = document.createElement("li"); li.textContent = i; fragment.appendChild(li); } list.appendChild(fragment); }
優化後的程式碼主要是建立了一個fragment,每次生成的li節點先新增到fragment,最後一次性新增到list,大家可以看示例
建立型API總結
建立型api主要包括createElement,createTextNode,cloneNode和createDocumentFragment四個方法,需要注意下面幾點:
(1)它們建立的節點只是一個孤立的節點,要通過appendChild新增到文件中
(2)cloneNode要注意如果被複制的節點是否包含子節點以及事件繫結等問題
(3)使用createDocumentFragment來解決新增大量節點時的效能問題
頁面修改型API
前面我們提到建立型api,它們只是建立節點,並沒有真正修改到頁面內容,而是要呼叫appendChild來將其新增到文件樹中。我在這裡將這類會修改到頁面內容歸為一類。
修改頁面內容的api主要包括:appendChild,insertBefore,removeChild,replaceChild。
appendChild
appendChild我們在前面已經用到多次,就是將指定的節點新增到呼叫該方法的節點的子元素的末尾。呼叫方法如下:
parent.appendChild(child);
child節點將會作為parent節點的最後一個子節點。
appendChild這個方法很簡單,但是還有有一點需要注意:如果被新增的節點是一個頁面中存在的節點,則執行後這個節點將會新增到指定位置,其原本所在的位置將移除該節點,也就是說不會同時存在兩個該節點在頁面上,相當於把這個節點移動到另一個地方。我們來看例子
<div id="child"> 要被新增的節點 </div> <br/> <br/> <br/> <div id="parent"> 要移動的位置 </div> <input id="btnMove" type="button" value="移動節點" /> document.getElementById("btnMove").onclick = function(){ var child = document.getElementById("child"); document.getElementById("parent").appendChild(child); }
這段程式碼主要是獲取頁面上的child節點,然後新增到指定位置,可以看到原本的child節點被移動到parent中了。
這裡還有一個要注意的點:如果child繫結了事件,被移動時,它依然繫結著該事件。
insertBefore
insertBefore用來新增一個節點到一個參照節點之前,用法如下:
parentNode.insertBefore(newNode,refNode);
parentNode表示新節點被新增後的父節點
newNode表示要新增的節點
refNode表示參照節點,新節點會新增到這個節點之前
我們來看這個例子
<div id="parent"> 父節點 <div id="child"> 子元素 </div> </div> <input type="button" id="insertNode" value="插入節點" /> var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.getElementById("insertNode").onclick = function(){ var newNode = document.createElement("div"); newNode.textContent = "新節點" parent.insertBefore(newNode,child); }
這段程式碼建立了一個新節點,然後新增到child節點之前。
和appendChild一樣,如果插入的節點是頁面上的節點,則會移動該節點到指定位置,並且保留其繫結的事件。
關於第二個引數參照節點還有幾個注意的地方:
(1)refNode是必傳的,如果不傳該引數會報錯
(2)如果refNode是undefined或null,則insertBefore會將節點新增到子元素的末尾
removeChild
removeChild顧名思義,就是刪除指定的子節點並返回,用法如下:
var deletedChild = parent.removeChild(node);
deletedChild指向被刪除節點的引用,它等於node,被刪除的節點仍然存在於記憶體中,可以對其進行下一步操作。
注意:如果被刪除的節點不是其子節點,則程式將會報錯。我們可以通過下面的方式來確保可以刪除:
if(node.parentNode){ node.parentNode.removeChild(node); }
通過節點自己獲取節點的父節點,然後將自身刪除。
replaceChild
replaceChild用於使用一個節點替換另一個節點,用法如下
parent.replaceChild(newChild,oldChild);
newChild是替換的節點,可以是新的節點,也可以是頁面上的節點,如果是頁面上的節點,則其將被轉移到新的位置
oldChild是被替換的節點
頁面修改型API總結
頁面修改型api主要是這四個介面,要注意幾個特點:
(1)不管是新增還是替換節點,如果新增或替換的節點是原本存在頁面上的,則其原來位置的節點將被移除,也就是說同一個節點不能存在於頁面的多個位置
(2)節點本身繫結的事件會不會消失,會一直保留著。
節點查詢型API
節點查詢型API也是非常常用的api,下面我們分別說明一下每一個api的使用。
document.getElementById
這個介面很簡單,根據元素id返回元素,返回值是Element型別,如果不存在該元素,則返回null。
使用這個介面有幾點要注意:
(1)元素的Id是大小寫敏感的,一定要寫對元素的id
(2)HTML文件中可能存在多個id相同的元素,則返回第一個元素
(3)只從文件中進行搜尋元素,如果建立了一個元素並指定id,但並沒有新增到文件中,則這個元素是不會被查詢到的
document.getElementsByTagName
這個介面根據元素標籤名獲取元素,返回一個即時的HTMLCollection型別,什麼是即時的HTMLCollection型別呢?我們來看看這個示例
<div>div1</div> <div>div2</div> <input type="button" value="顯示數量" id="btnShowCount"/> <input type="button" value="新增div" id="btnAddDiv"/> var divList = document.getElementsByTagName("div"); document.getElementById("btnAddDiv").onclick = function(){ var div = document.createElement("div"); div.textContent ="div" + (divList.length+1); document.body.appendChild(div); } document.getElementById("btnShowCount").onclick = function(){ alert(divList.length); }
這段程式碼中有兩個按鈕,一個按鈕是顯示HTMLCollection元素的個數,另一個按鈕可以新增一個div標籤到文件中。前面提到HTMLCollcetion元素是即時的表示該集合是隨時變化的,也就是是文件中有幾個div,它會隨時進行變化,當我們新增一個div後,再訪問HTMLCollection時,就會包含這個新增的div。
使用document.getElementsByTagName這個方法有幾點要注意:
(1)如果要對HTMLCollection集合進行迴圈操作,最好將其長度快取起來,因為每次迴圈都會去計算長度,暫時快取起來可以提高效率
(2)如果沒有存在指定的標籤,該介面返回的不是null,而是一個空的HTMLCollection
(3)“*”表示所有標籤
document.getElementsByName
getElementsByName主要是通過指定的name屬性來獲取元素,它返回一個即時的NodeList物件。
使用這個介面主要要注意幾點:
(1)返回物件是一個即時的NodeList,它是隨時變化的
(2)在HTML元素中,並不是所有元素都有name屬性,比如div是沒有name屬性的,但是如果強制設定div的name屬性,它也是可以被查詢到的
(3)在IE中,如果id設定成某個值,然後傳入getElementsByName的引數值和id值一樣,則這個元素是會被找到的,所以最好不好設定同樣的值給id和name
document.getElementsByClassName
這個API是根據元素的class返回一個即時的HTMLCollection,用法如下
var elements = document.getElementsByClassName(names);
這個介面有下面幾點要注意:
(1)返回結果是一個即時的HTMLCollection,會隨時根據文件結構變化
(2)IE9以下瀏覽器不支援
(3)如果要獲取2個以上classname,可傳入多個classname,每個用空格相隔,例如
var elements = document.getElementsByClassName("test1 test2");
document.querySelector和document.querySelectorAll
這兩個api很相似,通過css選擇器來查詢元素,注意選擇器要符合CSS選擇器的規則。
首先來介紹一下document.querySelector。
document.querySelector返回第一個匹配的元素,如果沒有匹配的元素,則返回null。
注意,由於返回的是第一個匹配的元素,這個api使用的深度優先搜尋來獲取元素。我們來看這個例子:
<div> <div> <span class="test">第三級的span</span> </div> </div> <div class="test"> 同級的第二個div </div> <input type="button" id="btnGet" value="獲取test元素" /> document.getElementById("btnGet").addEventListener("click",function(){ var element = document.querySelector(".test"); alert(element.textContent); })
這個例子很簡單,就是兩個class都包含“test”的元素,一個在文件樹的前面,但是它在第三級,另一個在文件樹的後面,但它在第一級,通過querySelector獲取元素時,它通過深度優先搜尋,拿到文件樹前面的第三級的元素。
document.querySelectorAll的不同之處在於它返回的是所有匹配的元素,而且可以匹配多個選擇符,我們來看看下面這個例子
<div class="test"> class為test </div> <div id="test"> id為test </div> <input id="btnShow" type="button" value="顯示內容" /> document.getElementById("btnShow").addEventListener("click",function(){ var elements = document.querySelectorAll("#test,.test"); for(var i = 0,length = elements.length;i<length;i++){ alert(elements[i].textContent); } })
這段程式碼通過querySelectorAll,使用id選擇器和class選擇器選擇了兩個元素,並依次輸出其內容。要注意兩點:
(1)querySelectorAll也是通過深度優先搜尋,搜尋的元素順序和選擇器的順序無關
(2)返回的是一個非即時的NodeList,也就是說結果不會隨著文件樹的變化而變化
相容性問題:querySelector和querySelectorAll在ie8以下的瀏覽器不支援。
節點關係型api
在html文件中的每個節點之間的關係都可以看成是家譜關係,包含父子關係,兄弟關係等等,下面我們依次來看看每一種關係。
父關係型api
parentNode:每個節點都有一個parentNode屬性,它表示元素的父節點。Element的父節點可能是Element,Document或DocumentFragment。
parentElement:返回元素的父元素節點,與parentNode的區別在於,其父節點必須是一個Element,如果不是,則返回null
兄弟關係型api
previousSibling:節點的前一個節點,如果該節點是第一個節點,則為null。注意有可能拿到的節點是文字節點或註釋節點,與預期的不符,要進行處理一下。
previousElementSibling:返回前一個元素節點,前一個節點必須是Element,注意IE9以下瀏覽器不支援。
nextSibling:節點的後一個節點,如果該節點是最後一個節點,則為null。注意有可能拿到的節點是文字節點,與預期的不符,要進行處理一下。
nextElementSibling:返回後一個元素節點,後一個節點必須是Element,注意IE9以下瀏覽器不支援。
子關係型api
childNodes:返回一個即時的NodeList,表示元素的子節點列表,子節點可能會包含文字節點,註釋節點等。
children:一個即時的HTMLCollection,子節點都是Element,IE9以下瀏覽器不支援。
firstNode:第一個子節點
lastNode:最後一個子節點
hasChildNodes方法:可以用來判斷是否包含子節點。
元素屬性型api
setAttribute
setAttribute:根據名稱和值修改元素的特性,用法如下。
element.setAttribute(name, value);
其中name是特性名,value是特性值。如果元素不包含該特性,則會建立該特性並賦值。
如果元素本身包含指定的特性名為屬性,則可以世界訪問屬性進行賦值,比如下面兩條程式碼是等價的:
element.setAttribute("id","test"); element.id = "test";
getAttribute
getAttribute返回指定的特性名相應的特性值,如果不存在,則返回null或空字串。用法如下:
var value = element.getAttribute("id");
元素樣式型api
window.getComputedStyle
window.getComputedStyle是用來獲取應用到元素後的樣式,假設某個元素並未設定高度而是通過其內容將其高度撐開,這時候要獲取它的高度就要用到getComputedStyle,用法如下:
var style = window.getComputedStyle(element[, pseudoElt]);
element是要獲取的元素,pseudoElt指定一個偽元素進行匹配。
返回的style是一個CSSStyleDeclaration物件。
通過style可以訪問到元素計算後的樣式
getBoundingClientRect
getBoundingClientRect用來返回元素的大小以及相對於瀏覽器可視視窗的位置,用法如下:
var clientRect = element.getBoundingClientRect();
clientRect是一個DOMRect物件,包含left,top,right,bottom,它是相對於可視視窗的距離,滾動位置發生改變時,它們的值是會發生變化的。除了IE9以下瀏覽器,還包含元素的height和width等資料,具體可檢視連結
總結
本文主要總結了原生js中常用的操作DOM的api介面,主要為了複習基礎知識。平時開發用多了jQuery等類庫,對基礎知識的瞭解可能就漸漸地遺忘,但這些基礎知識才是我們立足的根本,只有掌握原生的js,才能真正做好js的開發。
相關文章
- Javascript操作DOM常用API總結JavaScriptAPI
- JavaScript操作DOM常用的APIJavaScriptAPI
- Javascript-DOM基本操作總結(1)JavaScript
- JavaScript5:常用DOM操作JavaScript
- javascript中字串常用操作總結JavaScript字串
- JavaScript的字串、陣列以及DOM操作總結JavaScript字串陣列
- 1.14 JavaScript5:常用DOM操作JavaScript
- JS中DOM操作總結JS
- Javascript DOM學習總結JavaScript
- DOM常用操作
- DOM 常用 API 解析API
- phaser常用API總結API
- java常用Api總結JavaAPI
- jQuery知識總結之DOM操作jQuery
- JS知識總結之DOM操作JS
- js中Dom操作的個人總結JS
- ?Git 常用操作總結Git
- DataTable常用操作總結
- JavaScript DOM、BOM操作JavaScript
- javascript DOM的操作JavaScript
- JavaScript DOM位置尺寸APIJavaScriptAPI
- [Javascript] Manipulate the DOM with the classList APIJavaScriptAPI
- javascript字串常用api使用匯總(二)JavaScript字串API
- javascript快速入門21--DOM總結JavaScript
- 使用原生 JavaScript 操作 DOMJavaScript
- Javascript Object常用方法總結JavaScriptObject
- 操作solr replication的API總結SolrAPI
- 【Javascript】DOM程式設計學習總結篇JavaScript程式設計
- 前端新手必看的JavaScript常用DOM操作方法和函式前端JavaScript函式
- 前端開發常用cdn,api總結前端API
- 【JavaScript】DOM之樣式操作JavaScript
- JavaScript基礎之DOM操作JavaScript
- JavaScript 操作DOM效能優化JavaScript優化
- JavaScript入門⑦-DOM操作大全JavaScript
- JavaScript 操作 DOM 的那些坑JavaScript
- JavaScript學習總結(三)BOM和DOM詳解JavaScript
- javascript中!=、!==、==、===操作符總結JavaScript
- redis 常用api操作RedisAPI