DOM的操作(增刪改查)


操作DOM的核心就是增刪改查

目錄

一、節點創建型API

  • 1.1 createElement
  • 1.2 createTextNode
  • 1.3 cloneNode
  • 1.4 createDocumentFragment

二、頁面修改形API(包括刪除和添加)(刪)(改)

  • 2.1 appendChild(追加為子元素)
  • 2.2 insertBefore(插入前面)
  • 2.3 removeChild(刪除子元素)
  • 2.4 replaceChild(替換子元素)

三 節點查詢型API(查)

  • 3.1 document.getElementById
  • 3.2 document.getElementsByTagName
  • 3.3 document.getElementsByName
  • 3.4 document.getElementsByClassName
  • 3.5 document.querySelector和document.querySelectorAll
  • 3.6 elementFromPoint()

四 元素屬性型操作(屬性節點的操作)

一般只操作html標簽上的屬性如id;class之類的;
但是style屬性如寬高背景色之類的一般寫在css里面所以要通過element.currentStyle : window.getComputedStyle(element,pseduoElement)來操作詳細請看BOM筆記

  • 4.1 getAttribute() (獲取屬性)
  • 4.2 createAttribute() (創建屬性)
  • 4.3 setAttribute() (設置屬性)
  • 4.4 romoveAttribute() (刪除屬性)
  • 4.5 element.attributes(將屬性生成數組對象)

五 innerText和innerHTML(outerHTML)有什么區別?


DOM基本操作思維導圖


 
dom

一、節點創建型API(增)

在這里,我將常用的DOM操作api進行分類,首先要介紹的是創建型的api。這一類型的api,簡而言之就是用來創建節點的

1.1 createElement

createElement通過傳入指定的一個標簽名來創建一個元素,如果傳入的標簽名是一個未知的,則會創建一個自定義的標簽,注意:IE8以下瀏覽器不支持自定義標簽

var div = document.createElement("div"); 

使用createElement要注意:通過createElement創建的元素並不屬於html文檔,它只是創建出來,並未添加到html文檔中,要調用appendChild或insertBefore等方法將其添加到HTML文檔樹中;

1.2 createTextNode

createTextNode用來創建一個文本節點,用法如下

var textNode = document.createTextNode("一個TextNode"); 

createTextNode接收一個參數,這個參數就是文本節點中的文本,和createElement一樣,創建后的文本節點也只是獨立的一個節點,同樣需要append Child將其添加到HTML文檔樹中

1.3 cloneNode

cloneNode是用來返回調用方法的節點的一個副本,它接收一個bool參數,用來表示是否復制子元素,使用如下:

var parent = document.getElementById("parentElement"); var parent2 = parent.cloneNode(true);// 傳入true parent2.id = "parent2"; 

這段代碼通過cloneNode復制了一份parent元素,其中cloneNode的參數為true,表示parent的子節點也被復制,如果傳入false,則表示只復制了parent節點

<body> <div id="parent"> 我是父元素的文本 <br/> <span> 我是子元素 </span> </div> <button id="btnCopy">復制</button> <script> var parent = document.getElementById("parent"); //點擊id="btnCopy"點擊執行執行函數(函數內是一個元素的拷貝) document.getElementById("btnCopy").onclick = function(){ var parent2 = parent.cloneNode(true); parent2.id = "parent2"; document.body.appendChild(parent2); } </script> </body> 

這段代碼很簡單,主要是綁定button事件,事件內容是復制了一個parent,修改其id,然后添加到文檔中

這里有幾點要注意:
和createElement一樣,cloneNode創建的節點只是游離有html文檔外的節點,要調用appendChild方法才能添加到文檔樹中
如果復制的元素有id,則其副本同樣會包含該id,由於id具有唯一性,所以在復制節點后必須要修改其id
調用接收的bool參數最好傳入,如果不傳入該參數,不同瀏覽器對其默認值的處理可能不同
除此之外,我們還有一個需要注意的點:
如果被復制的節點綁定了事件,則副本也會跟着綁定該事件嗎?這里要分情況討論:
如果是通過addEventListener或者比如onclick進行綁定事件,則副本節點不會綁定該事件
如果是內聯方式綁定比如
<div onclick="showParent()"></div>
這樣的話,副本節點同樣會觸發事件

1.4 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

1.5 創建型API總結

創建型api主要包括

  • createElement
  • createTextNode
  • cloneNode
  • createDocumentFragment

四個方法.

需要注意下面幾點:

  • 它們創建的節點只是一個孤立的節點,
  • 要通過appendChild添加到文檔中
  • cloneNode要注意如果被復制的節點是否包含子節點以及事件綁定等問題
  • 使用createDocumentFragment來解決添加大量節點時的性能問題

二、頁面修改形API(包括刪除和添加)(刪)(改)

前面我們提到創建型api,它們只是創建節點,並沒有真正修改到頁面內容,而是要調用appendChild來將其添加到文檔樹中。我在這里將這類會修改到頁面內容歸為一類。

修改頁面內容的api主要包括

  • appendChild(追加為子元素)
  • insertBefore(插入前面)
  • removeChild(刪除子元素)
  • replaceChild(替換子元素)

2.1 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="移動節點" /> <script> document.getElementById("btnMove").onclick = function(){ var child = document.getElementById("child"); document.getElementById("parent").appendChild(child); } </script> 

這段代碼主要是獲取頁面上的child節點,然后添加到指定位置,可以看到原本的child節點被移動到parent中了。
這里還有一個要注意的點:如果child綁定了事件,被移動時,它依然綁定着該事件

2.2 insertBefore

insertBefore用來添加一個節點到一個參照節點之前,用法如下

parentNode.insertBefore(newNode,refNode); 

parentNode表示新節點被添加后的父節點
newNode表示要添加的節點
refNode表示參照節點,新節點會添加到這個節點之前

<div id="parent"> 父節點 <div id="child">子元素</div> </div> <input type="button" id="insertNode" value="插入節點" /> <script> 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); } </script> 

這段代碼創建了一個新節點,然后添加到child節點之前

和appendChild一樣,如果插入的節點是頁面上的節點,則會移動該節點到指定位置,並且保留其綁定的事件。

關於第二個參數參照節點還有幾個注意的地方:

  • refNode是必傳的,如果不傳該參數會報錯
  • 如果refNode是undefined或null,則insertBefore會將節點添加到子元素的末尾

2.3 removeChild

let oldChild = node.removeChild(child); //OR element.removeChild(child); 
  • child 是要移除的那個子節點.
  • node 是child的父節點.
  • oldChild保存對刪除的子節點的引用. oldChild === child.

被移除的這個子節點仍然存在於內存中,只是沒有添加到當前文檔的DOM樹中,因此,你還可以把這個節點重新添加回文檔中,當然,實現要用另外一個變量比如上例中的oldChild來保存這個節點的引用. 如果使用上述語法中的第二種方法, 即沒有使用 oldChild 來保存對這個節點的引用, 則認為被移除的節點已經是無用的,在短時間內將會被內存管理回收.

如果上例中的child節點不是node節點的子節點,則該方法會拋出異常.

// 先定位父節點,然后刪除其子節點 var d = document.getElementById("top"); var d_nested = document.getElementById("nested"); var throwawayNode = d.removeChild(d_nested); // 無須定位父節點,通過parentNode屬性直接刪除自身 var node = document.getElementById("nested"); if (node.parentNode) { node.parentNode.removeChild(node); } // 移除一個元素節點的所有子節點 var element = document.getElementById("top"); while (element.firstChild) { element.removeChild(element.firstChild); } 

2.4 replaceChild

replaceChild用於使用一個節點替換另一個節點,用法如下

parent.replaceChild(newChild,oldChild); 

newChild是替換的節點,可以是新的節點,也可以是頁面上的節點,如果是頁面上的節點,則其將被轉移到新的位置
oldChild是被替換的節點

2.5 頁面修改型API總結

頁面修改型api主要是這四個接口,要注意幾個特點:
不管是新增還是替換節點,如果新增或替換的節點是原本存在頁面上的,則其原來位置的節點將被移除,也就是說同一個節點不能存在於頁面的多個位置
節點本身綁定的事件會不會消失,會一直保留着


三 節點查詢型API(查)

節點查詢型API也是非常常用的

3.1 document.getElementById

這個接口很簡單,根據元素id返回元素,返回值是Element類型,如果不存在該元素,則返回null

使用這個接口有幾點要注意:

  • 元素的Id是大小寫敏感的,一定要寫對元素的id
  • HTML文檔中可能存在多個id相同的元素,則返回第一個元素
  • 只從文檔中進行搜索元素,如果創建了一個元素並指定id,但並沒有添加到文檔中,則這個元素是不會被查找到的

3.2 document.getElementsByTagName

這個接口根據元素標簽名獲取元素,返回一個即時的HTMLCollection類型,什么是即時的HTMLCollection類型呢?

<div>div1</div> <div>div2</div> <input type="button" value="顯示數量" id="btnShowCount"/> <input type="button" value="新增div" id="btnAddDiv"/> <script> 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); } </script> 

這段代碼中有兩個按鈕,一個按鈕是顯示HTMLCollection元素的個數,另一個按鈕可以新增一個div標簽到文檔中。前面提到HTMLCollcetion元素是即時的表示該集合是隨時變化的,
可以看出其實document.getElementsByTagName返回的是一個數組對象我們可以用數組的方式對其進行操作。

使用document.getElementsByTagName這個方法有幾點要注意:

  • 如果要對HTMLCollection集合進行循環操作,最好將其長度緩存起來,因為每次循環都會去計算長度,暫時緩存起來可以提高效率
  • 如果沒有存在指定的標簽,該接口返回的不是null,而是一個空的HTMLCollection
  • 參數“*”表示所有標簽

3.3 document.getElementsByName

getElementsByName主要是通過指定的name屬性來獲取元素,它返回一個即時的NodeList(節點列表)對象。一般用於獲取表單元素的·name·屬性

使用這個接口主要要注意幾點:

  • 返回對象是一個即時的NodeList,它是隨時變化的
  • 在HTML元素中,並不是所有元素都有name屬性,比如div是沒有name屬性的,但是如果強制設置div的name`屬性,它也是可以被查找到的
  • 在IE中,如果id設置成某個值,然后傳入getElementsByName的參數值和id值一樣,則這個元素是會被找到的,所以最好不好設置同樣的值給id和name

3.4 document.getElementsByClassName

這個API是根據元素的class返回一個即時的HTMLCollection,用法如下

var elements = document.getElementsByClassName(names); 

這個接口有下面幾點要注意:

  • 返回結果是一個即時的HTMLCollection,會隨時根據文檔結構變化
  • IE9以下瀏覽器不支持
  • 如果要獲取2個以上classname,可傳入多個classname,每個用空格相隔,例如var elements = document.getElementsByClassName("test1 test2");

3.5 document.querySelector和document.querySelectorAll

這兩個api很相似,通過css選擇器來查找元素,注意選擇器要符合CSS選擇器的規則

document.querySelector

querySelector方法返回匹配指定的CSS選擇器的元素節點。如果有多個節點滿足匹配條件,則返回第一個匹配的節點。如果沒有發現匹配的節點,則返回null。

var el1 = document.querySelector(".myclass"); var el2 = document.querySelector('#myParent > [ng-click]'); 

querySelector方法無法選中CSS偽元素。

注意,由於返回的是第一個匹配的元素,這個api使用的深度優先搜索來獲取元素

<div> <div> <span class="test">第三級的span</span> </div> </div> <div class="test"> 同級的第二個div </div> <input type="button" id="btnGet" value="獲取test元素" /> <script> document.getElementById("btnGet").addEventListener("click",function(){ var element = document.querySelector(".test"); alert(element.textContent); }) </script> 

這個例子很簡單,就是兩個class都包含“test”的元素,一個在文檔樹的前面,但是它在第三級,另一個在文檔樹的后面,但它在第一級,通過querySelector獲取元素時,它通過深度優先搜索,拿到文檔樹前面的第三級的元素(文檔樹前面優先深度優先)

document.querySelectorAll

document.querySelectorAll的不同之處在於它返回的是所有匹配的元素,querySelectorAll方法的參數,可以是逗號分隔的多個CSS選擇器,返回所有匹配其中一個選擇器的元素。

var matches = document.querySelectorAll("div.note, div.alert"); 

例子

<div class="test"> class為test </div> <div id="test"> id為test </div> <input id="btnShow" type="button" value="顯示內容" /> <script> 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); } }) </script> 

這段代碼通過querySelectorAll,使用id選擇器和class選擇器選擇了兩個元素,並依次輸出其內容。要注意兩點:

  • querySelectorAll也是通過深度優先搜索,搜索的元素順序和選擇器的順序無關
  • 返回的是一個非即時的NodeList,也就是說結果不會隨着文檔樹的變化而變化

兼容性問題:querySelector和querySelectorAll在ie8以下的瀏覽器不支持

3.6 elementFromPoint()

elementFromPoint方法返回位於頁面指定位置的元素。

var element = document.elementFromPoint(x, y); 

上面代碼中,elementFromPoint方法的參數x和y,分別是相對於當前窗口左上角的橫坐標和縱坐標,單位是CSS像素。

elementFromPoint方法返回位於這個位置的DOM元素,如果該元素不可返回(比如文本框的滾動條),則返回它的父元素(比如文本框)。如果坐標值無意義(比如負值),則返回null。

小結:

  • document.getElementById返回一個對象
  • document.getElementsByName和document.getElementsByClasName返回一個對象數組

四 元素屬性型操作(屬性節點的操作)

4.1 getAttribute()(獲取屬性)

getAttribute()用於獲取元素的attribute值

node.getAttribute('id'); //表示獲取node元素的id屬性的 ‘值’ 

4.2 createAttribute()(創建屬性)

createAttribute()方法生成一個新的屬性對象節點,並返回它。

attribute = document.createAttribute(name); createAttribute方法的參數name,是屬性的名稱。 

4.3 setAttribute()(設置屬性)

setAttribute()方法用於設置元素屬性

var node = document.getElementById("div1"); node.setAttribute(name, value); //name為屬性名稱 ;value為屬性值 例如 var node = document.getElementById("div1"); node.setAttribute("id", "ct"); 等同於 var node = document.getElementById("div1"); var a = document.createAttribute("id"); a.value = "ct"; node.setAttributeNode(a); 

4.4 romoveAttribute()(刪除屬性)

removeAttribute()用於刪除元素屬性

node.removeAttribute('id'); 

4.5 element.attributes(將屬性生成數組對象)

當然上面的方法做的事情也可以通過類似操作數組屬性element.attributes來實現

語法

var attr = element.attributes; 

示例

// 獲取文檔的第一個 <p> 元素 var para = document.getElementsByTagName("p")[0]; //獲取該元素屬性(多個屬性會形成一個數組對象) var atts = para.attributes; 

遍歷元素的屬性
索引有利於遍歷一個元素的所有屬性。

在以下例子中會遍歷文檔中 id 為 "paragraph" 元素的屬性節點,並打印出來。

<p id="paragraph" style="color: green;">Sample Paragraph</p> <form action=""> <p> <input type="button" value="顯示第一個屬性及其值" onclick="showFirstAttr();"> <input id="result" type="text" value=""> </p> </form> <script type="text/javascript"> function showFirstAttr() { var paragraph= document.getElementById("paragraph"); var result= document.getElementById("result"); // 首先,讓我們確認這個段落有一些屬性。 //hasAttributes屬性返回一個布爾值true或false,來表明當前元素節點是否有至少一個的屬性(attribute). if (paragraph.hasAttributes()) { var attrs = paragraph.attributes; var output= ""; for(var i=attrs.length-1; i>=0; i--) { output+= attrs[i].name + "->" + attrs[i].value; } result.value = output; //寫入 value=""使文本框出現內容 } else { result.value = "沒有屬性顯示了" //寫入 value="沒有屬性顯示了"使文本框出現內容 } } </script> 

五 innerText和innerHTML(outerHTML)有什么區別?

innerText

innerText是一個可寫屬性,返回元素內包含的文本內容,在多層次的時候會按照元素由淺到深的順序拼接其內容

<div id="test"> <!--注釋--> <p>我的名字叫<span>哈哈哈</span></p> </div> <script> var test = document.getElementById('test') console.log(test.innerText); </script> 

返回的結果

‘我的名字叫哈哈哈’

只包含文本節點

innerHTML、outerHTML

innerHTML屬性作用和innerText類似,但是不是返回元素的文本內容,而是返回元素的HTML結構,在寫入的時候也會自動構建DOM

<div id="test"> <!--注釋--> <p>我的名字叫<span>哈哈哈</span></p> </div> <script> var test = document.getElementById('test') console.log(test.innerHTML); </script> 

返回的結果

 <!--注釋--> <p>我的名字叫<span>哈哈哈</span></p> 

包含整個html結構;(元素節點、注釋節點、文本節點)


<div id="test"> <!--注釋--> <p>我的名字叫<span>哈哈哈</span></p> </div> <script> var test = document.getElementById('test') console.log(test.outerHTML); </script> 

返回的結果

<div id="test"> <p>我的名字叫<span>哈哈哈</span></p> </div> 

包括自身和包含整個html結構;(元素節點、注釋節點、文本節點)

區別:

  • innerText返回的是元素內包含的文本內容(只返回文本節點類型);
  • innerHTML返會元素內HTML結構,包括元素節點、注釋節點、文本節點;
  • outerHTML返回包括元素節點自身和里面的所有元素節點、注釋節點、文本節點;


作者:動感超逗
鏈接:https://www.jianshu.com/p/b0aa846f4dcc
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM