---
# System prepended metadata

title: DOM 節點操作練習
tags: [DOM, DOM操作, javascript, addEventListener]

---



React 寫久了，對於 DOM 節點的操作變的好不熟悉啊! :scream_cat: 
最近收到一個 Javascript 的前端面試題，剛好複習 DOM 節點的操作。

## 在這之前，先了解 DOM 是什麼?

DOM 的全稱是 Document Object Model 文件物件模型，是一個像樹狀圖的文件結構。

![](https://hackmd.io/_uploads/S1XLYjY_h.png)

當瀏覽器讀取文件檔案，會按照形成 DOM tree 的結構節點去渲染出畫面，並定義讓程式可以存取並改變文件架構、風格和內容的方法。

也就是說，我們可以利用 JS 的方法去查看存取渲染樹中的節點，去新增、刪除、修改、替換其他節點(元素)、去添加 class 更改呈現樣式，也可以附加事件處理程序，一旦觸發事件就會執行處理程序。

最常用的使用方式是配合使用者的互動去改動節點。
先來看看語法，我們再來看如何使用會更有感覺~

## 有哪些 DOM 操作使用方法?

### 找到節點
Document 的方法，先來介紹 **querySelector 和 querySelectorAll**

querySelector 很好用，可以去幫我們找到特定的節點，不管你要找 class, id, 還是特定的節點都可以。
如果真的找不到指定節點，他就會回傳 null。

**querySelector(selectors)**

```

<div id="box"></div>
<div class="box"></div>
<p> Hi </p>

// 複雜版本的節點
<div class="complex main">
  <input type="checkbox"/>
</div>

<script>
 const idElement = document.querySelector("#box")
 const classElement= document.querySelector(".box")
const pElement = document.querySelector("p")
 const complexElement = document.querySelector("div.complex.main input[type='checkbox']")
</script>
```
至於 querySelectorAll，就如字面上來說，幫助你快速抓到所有節點的好幫手！

**querySelectorAll(selectors)**

```
<section id="box-wrapper">
  <div class="box">div <br>1</div>
  <div class="box">div <br>2</div>
  <div class="box">div <br>3</div>
  <div class="box">div <br>4</div>
</section>

<script>
const boxNodes = document.querySelectorAll('.box')
</script>
```

**繼續用別的方法來找到 HTML 元素**

| 方法 | 描述 |
| ---- | ---- |
| document.getElementById(id)     |  用 id 找到元素    |
| document.getElementsByTagName(name)     |      用標籤名稱找到元素|
| document.getElementsByClassName(name) | 用 class 找到元素 |

**改變 HTML 的元素**


| 屬性 | 描述 |
| -------- | -------- |
| element.innerHTML =  new html content         | 改變元素裡面的 HTML |
|  element.attribute = new value        |      改變 HTML 元素裡的屬性值    |
| element.style.property = new style         | 改變 HTML 元素的 style         |

| 方法         |  描述        |
| -------- | -------- |
| element.setAttribute(attribute, value)     |改變 HTML 元素裡的屬性值     |

**增加或刪除元素**


| 方法                            | 描述 |
| ------------------------------- | ---- |
| document.createElement(element) | 建立一個新的 html 元素|
| document.removeChild(element)                                | 移除一個 html 元素     |
| document.appendChild(element)                                | 加入一個 html 元素     |
| document.replaceChild(new, old)                                | 替換一個 html 元素      |
| document.insertBefore(new, original)                                | 插入一個元素在指定節點前     |


來用上面的 <selection></selection> box html 檔案來組合一下，如何用上方的方法來操作 DOM 節點。

```
const boxWrapper = document.getElementById("box-wrapper");

const box = document.createElement("div");
box.innerHTML = 'div <br> 5';
box.style.backgroundColor = "orange";
box.classList.add("box");

boxWrapper.appendChild(box);


```

**要注意  appendChild() 和 insertBefore() 加入節點的位置會再不一樣的地方**

Node: appendChild() method: 會加在父元素的最後一個節點
Node: insertBefore() method: 可將元素插入在父元素的某個節點前面

如果要做些操作判斷，也可以用 contains() 的方法判斷裡面有沒有特定的 class 

**element.classList.contains(className)**


## 加上 Event Listener


然後重點來了，**使用者互動要增加的 Event Handlers 來了!**

不過雖然這樣說，事件的發生要注意除了使用者互動，也有可能是來自 API 處理非同步任務所產生的。

只是這邊筆記會只講由使用者操作行為所產生的~

直接來兩種寫法 :arrow_down: 

**document.getElementById(id).onclick = function(){code}**

**EventTarget.addEventListener(事件, 執行函式 )**


選取節點以後，使用 addEventListener 綁定事件

document.querySelector('#newOptions').addEventListener('change', selectedFuc);

要看 selectedFun 這個函式做什麼，可以繼續往下看我使用 join() 的說明有用到 (就不占版面了!)


**小補充:** 講到事件觸發，就要記得這兩個常用的~
因為我今天差點忘了要加這個 Event.preventDefault() :laughing: 

**Event.preventDefault():** 是可以取消一些預設行為發生，例如表格裡的提交會自動刷新頁面，我今天的用法是想要按 submit 以後直接在同個頁面上取得資料來顯示，這時候就不能給它刷新了。

**Event.stopPropagation():** 是阻止事件的物件繼續捕捉或冒泡傳遞。

---


我在這次的問題用到 join()  
它要用來幹嘛呢? 

join() 方法會將陣列（或一個類陣列（array-like）物件）中所有的元素連接、合併成一個字串，並回傳此字串。

說明一下使用情境: 

我在所有選項上綁定 change 事件，勾選起來的選項，使用 value 空陣列都把它們推進去，如果取消勾選的就被篩出來。

最後再把它的值 map 出來，但我要把這個類陣列的元素都連接，才可以把它放進去，改變元素裡的 html 。


```
function selectedFuc(e) {
  if (e.target.checked) {
    const option = e.target.value;
    value.push(option);
  } else {
    const option = e.target.value;
    value = value.filter((item) => item !== option);
  }

  // 要將 value 的值動態呈現在 selectedContainer 的 input 裡
  const items = document.querySelector('.boxWrapper');
  const selectedItems = value.map(
    (item) => `
   <span>${item}</span>
`
  );

  console.log('selectedItems', selectedItems);
  const test = selectedItems.join('');
  console.log('test', test);
  items.innerHTML = selectedItems.join('');
}
```

可以看以下截圖比較 selectedItems 和 test 來看使用 Array.prototype.join() 的差別

![](https://hackmd.io/_uploads/Syn9kOYd3.png)


### 參考資料:

w3schools 、 MDN 

[JavaScript HTML DOM Document](https://www.w3schools.com/js/js_htmldom_document.asp)
