【SSD系列】沒了jquery, vue, react,你還會DOM節點的增刪改查嗎?

這是我參與8月更文挑戰的第10天,活動詳情查看:8月更文挑戰javascript

前言

關於【SSD系列】
前端一些有意思的內容,旨在3-10分鐘裏, 500-1500字,有所獲,又不爲所累。css

先提問一波:(無框架前提下)html

  • 經常使用查詢節點方法有哪些前端

  • 什麼是空白節點??她又究竟是個什麼東西vue

  • querySelectorAll 有哪些坑java

  • 怎麼查詢僞元素node

  • 四種刪除節點方式你都知道嗎react

  • HTMLCollection 和 NodeList的區別jquery

  • 怎樣刪除全部的孩子節點git

咱們已經先jquery, vue, react等前端框架帶來的便利了:

  • jquery就不說了,一個$走天下,無限連。
  • vue和react使用ref就能拿到對應節點。

離開了這些框架,你還能666的操做Node節點嗎?

本文源碼

crud-doms

節點查詢

先放一段測試的html代碼

<div class="outer" id="outer">
    <ul class="list list-1">
      <li class="item">list-one</li>
      <li class="item">list-two</li>
      <li class="item">list-three</li>
    </ul>
  </div>

  <input type="button" name="btnSubmit" value="刷新"/>
複製代碼

經常使用的節點查詢方法

  1. getElementById

    根據元素的id屬性值進行節點查詢,返回單一節點。

    document.getElementById("outer")  // <div class="outer" id="outer">......
    複製代碼
  2. getElementsByClassName

    根據元素的classname屬性值就行查詢。

    document.getElementsByClassName("item") // HTMLCollection(3) [li.item, li.item, li.item]
    複製代碼
  3. getElementsByName

    根源節點的name屬性進行查詢。

    document.getElementsByName("btnSubmit") // NodeList [input]
    複製代碼
  4. getElementsByTagName

    根據節點標籤名進行查詢。

    document.getElementsByTagName("li") // HTMLCollection(3) [li.item, li.item, li.item]
    複製代碼
  5. querySelector

    根絕css選擇器進行節點查詢,返回單個節點。

    document.querySelector("#outer") // <div class="outer" id="outer">......
    複製代碼
  6. querySelectorAll

    根絕css選擇器進行節點查詢,返回節點列表。

    document.querySelectorAll(".item") // NodeList(3) [li.item, li.item, li.item]
    複製代碼

    在沒有querySelectorquerySelectorAll出現以前,基本都是經過前四個查詢方法配合 childNodesparentNode方法擴展出各類方法。

一些特殊查詢屬性

  • document.all 返回全部的節點
  • document.images 返回全部的圖片
  • document.forms 返回全部的form表單
  • document.links 返回全部的連接標籤
  • document.embeds 返回全部的 object標籤元素,之前主要用於flash,pdf等等

querySelectorAll 注意事項

  • 其返回的靜態的NodeList, 隨後對DOM元素的改動不會影響其集合的內容。

    下面的代碼能夠看到,添加一個節後後, nodeList長度並無變化。

    <ul class="list list-1">
        <li class="item">list-one</li>
        <li class="item">list-two</li>
        <li class="item">list-three</li>
      </ul>
    
      <script> var nodeList = document.querySelectorAll(".item"); console.log("len:", nodeList.length); // 3 var liEl = document.createElement("li"); liEl.className = "item"; liEl.innerHTML = "list-for" document.querySelector(".list").appendChild(liEl); console.log("len:", nodeList.length); //3  </script>
    複製代碼
  • querySelectorAll可能返回的不是你指望的值

    <div class="outer">
      <div class="select">
        <div class="inner">
        </div>
      </div>
    </div>
    
    <script> var select = document.querySelector('.select'); var inner = select.querySelectorAll('.outer .inner'); inner.length; // 1, not 0! </script>
    
    複製代碼

    那麼怎樣才能返回指望的結果呢?答案是 :scope

    var select = document.querySelector('.select');
    var inner = select.querySelectorAll(':scope .outer .inner');
    inner.length; // 0
    複製代碼
  • 轉義特殊字符

    <div id="foo\bar"></div>
      <div id="foo:bar"></div>
    
      <script> console.log('#foo\bar') // "#fooar" document.querySelector('#foo\bar') // 不匹配任何元素 console.log('#foo\\bar') // "#foo\bar" console.log('#foo\\\\bar') // "#foo\\bar" document.querySelector('#foo\\\\bar') // 匹配第一個div document.querySelector('#foo:bar') // 不匹配任何元素 document.querySelector('#foo\\:bar') // 匹配第二個div </script>
    複製代碼

HTMLCollection 和 NodeList的區別

細心的通知可能發現了,上面的方法,有的返回的是HTMLCollection,有的返回的是NodeList。 他們有什麼區別呢?

這裏先要弄清晰繼承關係:

HTMLElement -> Element -> Node-> EventTarget
複製代碼

EventTarget 前一個提供了事件分發能力,自己也是一個訂閱發佈中心,更多詳情參見 3行代碼一個訂閱發佈中心,不會不知道吧

Node 有 12種節點類型,詳情參見 NodeType,咱們經常使用的 div, span等等屬於nodeType=1的節點類型。

因此:

HTMLCollection 是元素節點類型,即nodeType爲1的節點。

NodeList 是節點集合,包含文本節點,註釋節點等等其餘節點。

怎麼查詢僞元素

// html代碼  
<style> .nihao::before{ content: '你好,'; } </style>
  <div class="nihao" id="nihao">
    Tom
  </div>
複製代碼

答案是不能,但你能夠經過 window.getComputedStyle 來獲取其樣式。

window.getComputedStyle(nihao, "before")["content"] // "\"你好,\""
複製代碼

節點刪除

先特出測試的html代碼段

<ul class="list list-1">
    <li class="item">list-one</li>
    <li class="item">list-two</li>
    <li class="item">list-three</li>
  </ul> 
複製代碼

Node.removeNode

這種咱們用的最多的方法,前提是首先得得到要被刪除元素的父節點,可使用parentNode或者parentElement得到。

var ul = document.querySelector(".list");
    console.log("li length", ul.children.length);  // 3
    ul.removeChild(ul.children[0])  // removeChild
    console.log("li length", ul.children.length); // 2

複製代碼

Element.remove

這個方法屬於 Element對象上,也就代表,其餘nodeType類型是不可使用的, 其不須要得到副節點。

var ul = document.querySelector(".list");
    console.log("li length", ul.children.length);  // 3
    ul.children[0].remove();  // remove
    console.log("li length", ul.children.length); // 2

複製代碼

outerHTML或者innerHTML

var ul = document.querySelector(".list");
    console.log("li length", ul.children.length);  // 3
    ul.children[0].outerHTML = null   // outerHTML
    console.log("li length", ul.children.length); // 2


複製代碼

Document.adoptNode

從其餘的document文檔中獲取一個節點。 該節點以及它的子樹上的全部節點都會從原文檔刪除。

var ul = document.querySelector(".list");
console.log("li length", ul.children.length);  // 3
document.adoptNode(ul.children[0]); // adoptNode
console.log("li length", ul.children.length); // 2

複製代碼

批量刪除節點

批量刪除,好比清除某個節點下的全部子節點,通常是使用while循環,暴力的方式是 innerHTML = null

innerHTML = null可能致使事件監聽器沒有被取消,以致使內存泄漏,具體有麼有,還得看瀏覽器的實現。

咱們封裝一個吧:

function clearChildNodes(node){
    while(node.hasChildNodes()){
        node.removeChild(node.firstChild);
    }
}
const ul = document.querySelector(".list");
console.log("nodes:", ul.childNodes.length);  // 7
clearChildNodes(ul);   
console.log("nodes:", ul.childNodes.length);  // 0
複製代碼

空白節點

爲何是7個節點呢? 看圖上的空白節點,有4個, 4+3 =7樓。

image.png

咱們調整一下代碼, 刪除空白,再看輸出

<ul class="list list-1"><li class="item">list-one</li><li class="item">list-two</li><li class="item">list-three</li></ul>
複製代碼

image.png

那空白節點,到底是個什麼東西??

看代碼,其實就是nodeType爲3的文本節點。進行輸出的時候其textConent爲空。

var ul = document.querySelector(".list");
    console.log("li length", ul.childNodes.length);  // 7

    var firstNode = ul.childNodes[0];
    console.log("nodeType", firstNode.nodeType);  // 3 
    console.log("content", firstNode.textContent); // 
複製代碼

咱們不妨添加一點內容, 你就能清晰的知道了, 其childNodes長度依舊是7,第一個文本節點的內容是 text content

<ul class="list list-1">text content
    <li class="item">list-one</li>
    <li class="item">list-two</li>
    <li class="item">list-three</li>
  </ul> 
複製代碼

image.png

小結

是否是很簡單,一切都看起來沒那麼難,這樣,你才容易入坑啊。

篇幅優先,若是star超過 100, 再寫一篇節點增長和更新的文章。

寫在最後

寫做不易,你的一讚一評就是我前行的最大動力。
技術交流羣,請加微信 dirge-cloud。

Node
HTMLElement
querySelectorAll

相關文章
相關標籤/搜索