---
# System prepended metadata

title: DOM 擷取網頁元素
tags: [DOM]

---

---
title: DOM 擷取網頁元素
tags: DOM,
description:
---

DOM（Document Object Model）
===

### 為什麼JavaScript檔案要放在``<body>``的結尾
- 因為要等``HTML``渲染完成後，``JavaScript``才能對畫面去做控制。
- 若``JavaScript``先執行，但``HTML``**尚未渲染完成**，選擇器無法對DOM做控制。
    ![](https://i.imgur.com/PDdlANE.png)
---
<br>

### querySelector 選擇器
:::success
#### ```document.querySelector('.title');```

#### ```在整個網頁.選取網頁元素的方法('css選擇器');```
:::

- **HTML**
```htmlmixed=
<body>
  <h1 class="title">JavaScript</h1>
  <script src="./all.js"></script>
</body>
```
- **JavaScript**
  - 選取```class="title"```選擇器，再賦予給變數``el``
  - 變數``el``的值，```<h1 class="title">JavaScript</h1>```，也就是變數``el``取得``.title``這個HTML元素

```javascript=
const el = document.querySelector('.title');
console.log(el);
```
<br>

**可以用==類似 CSS 的撰寫方式==選取**

- **HTML**
```htmlembedded=
<div id="targetID">
  <p>我被 elementID 選取到了</p>
</div>
<!-- 以下是 span 被選取到 -->
<div class="targetClass">
  <p>
    <span>我被 elementClass 選取到了</span>
  </p>
</div>
```
- **JavaScript**
```javascript=
const elementID = document.querySelector("#targetID p");
const elementClass = document.querySelector(".targetClass > p > span");
```

或者是

- **HTML**
```htmlembedded=
<div class="div">
    <p class="text">abcd</p>
  </div>
```

- **JavaScript**
```javascript=
const text = document.querySelector('.div .text');
```


---
<br>

### 選取HTML Tag的屬性 & 值

選取`<p>`的`data-message`的值

```htmlmixed=
<p class="orderInfo-message" data-message="姓名">必填</p>
```

在屬性及屬性值外加上`[]`。`[data-message="姓名]`
```javascript=
console.log(document.querySelector('[data-message="姓名"]'));
```
---
<br>


### 更改HTML元素內容

用css選擇器取得HTML元素，就能使用其他方法來修改內容。

- **.textContent 修改文字內容**
    ```htmlmixed=
    // HTML
    <body>
      <h1 class="title">JavaScript</h1>
      <script src="./all.js"></script>
    </body>
    ```
    針對已經選取的``h1``，==更改==文字內容
    ```el.textContent = 'J a v a S c r i p t ';```
    ```javascript=
    // JavaScript
    const el = document.querySelector('.title');
    el.textContent = 'J a v a S c r i p t ';
    ```
- **.innerHTML 插入HTML標籤**
    ```htmlmixed=
    // HTML
    <div class="div">
        <h3>12345</h3>
    </div>
    ```
    針對已經選取的**區塊元素**``div``，==插入==HTML標籤
    ``newContent.innerHTML = '<h2 class="title">54321</h2>'``
    
    :::danger
    插入HTML標籤後，原本區塊內HTML標籤會被清除取代
    :::
    ```javascript=
    // JavaScript
    const newContent = document.querySelector('.div');
    newContent.innerHTML = `<h2 class="title">54321</h2>`;
    ```
- **innerHTML加入變數**
正常用``innerHTML``插入HTML標籤，會取代原有區塊的標籤。
    ```htmlmixed=
    <ul class="list">
      <li>
        <a href="https://www.google.com.tw">google連結</a>
      </li>
    </ul>
    ```
    ```javascript=
    const el = document.querySelector('.list');
    el.innerHTML = `<li><a href="https://www.yahoo.com.tw">yahoo連結</a></li>`;
    ```
把JavaScript內容，用代入變數重構HTML標籤，讓innerHTML更有彈性，變化。
- 把``<a>``連結的``href``、文字內容，建立變數``href``、``linkContent``。
- 變數``htmlTag``用==樣板字面詞==引入變數使用。 
- 再把變數``htmlTag``賦予到``el.innerHTML``。
- 如果有多個``htmlTag``要插入，用變數相加的方式，、賦予到``el.innerHTML``。
```javascript=
const el = document.querySelector('.list');
let href = 'https://www.yahoo.com.tw';
let linkContent = 'yahoo連結';
let htmlTag = `<li><a href="${href}">${linkContent}</a></li>`
el.innerHTML = htmlTag + htmlTag;
```
---
<br>

### ``.textContent``與``.innerHTML``的差異處

- **.innerHTML**：呈現HTML標籤、DOM結構（屬性、文字）

```javascript=
// HTML
<div class="div"></div>

// JavaScript
const el = document.querySelector('.div');
el.innerHTML = `<h1>標題</h1>`;
```
![](https://i.imgur.com/S2LFaj3.png)![](https://i.imgur.com/v1tFXNT.png)
<br>

- **.textContent**：只有呈現文字部分
```javascript=
// HTML
<div class="div"></div>

// JavaScript
const el = document.querySelector('.div');
el.innerHTML = `<h1>標題</h1>`;
```
![](https://i.imgur.com/zsdW3Xh.png)
![](https://i.imgur.com/dLQHtic.png)

---
<br>

### textContent 可以跟變數混合使用

- **HTML**
```htmlembedded=
<div class="targetClass"></div>
```
- **JavaScript**
```javascript=
const targetClass = document.querySelector(".targetClass");
let score = 100;
targetClass.textContent = `<p>小華的成績為 ${score} 分</p>`;
```

結果：
(網頁渲染出的畫面)
![](https://i.imgur.com/GH77RQV.png)

(修改後的 HTML 結構)
![](https://i.imgur.com/ZrGcOr2.png)

---
<br>


### setAttribute 增加 HTML 標籤屬性
``.setAttribute('HTML屬性名稱','HTML屬性內容')``

增加``<a>``標籤屬性``class="red"``，搭配css將文字顏色改變成**紅色**

```htmlmixed=
<p>文字內容</p>
<style>
.red{
  color: red;
};
</style>
```
```javascript=
const text = document.querySelector('p');
text.setAttribute('class', 'red');
```
---
<br>

### .querySelectorAll 可重複選取多個元素

用``.querySelectorAll``取得``document``上面==多個重複==的HTML標籤。

```htmlmixed=
<ul class="list">
  <li><a href="">link1</a></li>
  <li><a href="">link2</a></li>
</ul>
```

```javascript=
const links = document.querySelectorAll('a');
console.log(links);
```
- ``.querySelectorAll('a')``，取得``document``上面重複的``<a>``標籤，賦予給變數``links``。
- 印出變數``links``的結果，得到==陣列==形式的多個``<a>``DOM節點資料。
  ![](https://i.imgur.com/2ft6RqX.png)
- 因為取得的是==陣列==形式的多個``<a>``DOM節點資料，可以對不同的DOM節點資料進行修改。
    ```javascript=
    const links = document.querySelectorAll('a');
    links[0].textContent = `google連結`;
    links[0].setAttribute('href', 'http://www.google.com.tw');
    links[1].textContent = `yahoo連結`;
    links[1].setAttribute('href', 'http://www.yahoo.com.tw');
    ```
---
<br>

### .innerHTML、.textContent、.getAttribute取值方法
- **``.getAttribute``取得屬性**

    ```htmlmixed=
    <div class="div">
      <h1 class="title">標題</h1>
    </div>
    ```
    - 選擇器先選取``<h1>``標籤，賦予變數``el``。
    - 再用``.getAttribute``取得``<h1>``的class屬性。
    ```javascript=
    const el = document.querySelector('h1');
    const content = el.getAttribute('class');
    console.log(content);    // title
    ```

- **``.textContent``取得文字內容**

    ```htmlmixed=
    <div class="div">
      <h1 class="title">標題</h1>
    </div>
    ```
    - 選擇器先選取``<h1>``標籤，賦予變數``el``。
    - 再用``.textContent``取得``<h1>``的文字內容。
    ```javascript=
    const el = document.querySelector('h1');
    const content = el.textContent;
    console.log(content);    // 標題
    ```
    
- **``.innerHTML``取得區塊節點結構**
    ```htmlmixed=
    <div class="div">
      <h1 class="title">標題</h1>
    </div>
    ```
    - 選擇器先選取``class``div標籤，賦予變數``el``。
    - 再用``.innerHTML``取得``<div>``內的節點結構。
    ```javascript=
    const el = document.querySelector('.div');
    const content = el.innerHTML;
    console.log(content);    //  <h1 class="title">標題</h1>
    ```
    ---
    <br>

### 表單元素取值方式

- **input取值**
    ```htmlmixed=
    <input type="text" class="input" value="你好嗎">
    ```
    - 選擇器先選取``class``input標籤，賦予變數``el``。
    - 再用```el.value```，取得input表單內容，再賦予給變數``content``。
    ```javascript=
    const el = document.querySelector('.input');
    const content = el.value;
    console.log(content);    // 你好嗎
    ```
    
- **select取值**
    ```htmlmixed=
    <label for="city">城市</label>
    <select name="city" class="cityList" id="city">
      <option value="台中">台中</option>
      <option value="高雄">高雄</option>
    </select>
    ```
    - 選擇器先選取``class``cityList標籤，賦予變數``selectOption``。
    - 再用```selectOption.value```，取得select表單內容，再賦予給變數``value``。
    ```javascript=
    const selectOption=document.querySelector('.cityList');
    const value = selectOption.value;
    console.log(value);    // 台中
    ```
    - **select取多個值**
    
      - 用``.querySelectorAll``取到select表單內全部的``option``，再賦予給變數``value``。
      - 變數``value``的資料結構，第一層是陣列，第二層是物件。
        ![](https://i.imgur.com/PrAx4HJ.png)
      - 第二層的物件屬性``length``，可以看見select表單內全部的``option``的資料長度。
        ![](https://i.imgur.com/OofKNRS.png)
      - 第二層的物件屬性0是第一個option內容，用``[0]``或``['0']``取屬性內容，再進去一層用.value取select表單``option``值。
      - 第二層的物件屬性1是第二個option內容，用``[1]``或``['1']``取屬性內容，再進去一層用.value取select表單``option``值。
        ![](https://i.imgur.com/zX3pd6I.png)

       ```javascript=
       const selectOption = document.querySelectorAll('.cityList');
       const value = selectOption;
       console.log(value);
       console.log(value[0]['0'].value);    // 台中
       console.log(value[0]['1'].value);    // 高雄
       ```
<br>
---

### `.value` 取出的值是「字串」
這邊以 input 的 value 取值為例，請觀看以下範例：

HTML
```htmlembedded=
<input type="text" id="targetInput">
<button type="button" id="triggerBtn">觸發按鈕</button>
```
JS
```javascript=
const el = document.querySelector('#targetInput');
const triggerBtn = document.querySelector('#triggerBtn');

triggerBtn.addEventListener('click', function(e){
    console.log(el.value);
    console.log(typeof(el.value));
})
```
如果在 input 輸入數字 123 以後點選「觸發按鈕」，可以在 console 中觀察到以下結果：

![](https://i.imgur.com/18bzrew.png)
> `.value` 取出來的值為字串

**因此如果要對表單的「數值」進行運算，請記得要先使用 `parseInt` 做型別轉換。**

範例如下：
HTML
```htmlembedded=
<input type="text" id="targetInput">
<button type="button" id="triggerBtn">觸發按鈕</button>
```
JS
```javascript=
const el = document.querySelector('#targetInput');
const triggerBtn = document.querySelector('#triggerBtn');

triggerBtn.addEventListener('click', function(e){
    let newValue = parseInt(el.value);  // 轉為 Number
    console.log(newValue);
    console.log(typeof(newValue));
})
```
結果：

![](https://i.imgur.com/k18ol8z.png)

<br>


### `.value`, `.getAttribute('value')` 的差異

HTML
```htmlembedded=
<input type="text" id="targetInput" value="123">
<button type="button" id="triggerBtn">觸發按鈕</button>
```
JS
```javascript=
const el = document.querySelector('#targetInput');
const triggerBtn = document.querySelector('#triggerBtn');
console.log(`el.value: ${el.value}`);

triggerBtn.addEventListener('click', function(e){
    el.value = "任意填入的值";
    console.log(`el.value: ${el.value}`);
})
```

console 結果：

![](https://i.imgur.com/HYHEDTk.png)


看到這邊，同學是不是認為 `<input type="text" id="targetInput" value="123">` 這行程式碼的 `value="123"` 應該已經被修改為 `value="任意填入的值"` 了? 

>不過，如果我們將程式碼修改如下，並一樣的點選「觸發按鈕」觀察結果:

HTML
```htmlembedded=
<input type="text" id="targetInput" value="123">
<button type="button" id="triggerBtn" >觸發按鈕</button>
```
JS
```javascript=
const el = document.querySelector('#targetInput');
const triggerBtn = document.querySelector('#triggerBtn');

triggerBtn.addEventListener('click', function(e){
    el.value = "任意填入的值";
    console.log(`el.value: ${el.value}`);
    console.log(`el.getAttribute('value'): ${el.getAttribute('value')}`);
})
```

可以發現網頁上 input 欄位「輸入的值」的確已經被更改為 "任意填入的值"

![](https://i.imgur.com/dI37ggU.png)

但是 `el.value` 與 `el.getAttribute('value')` 卻是不一樣的，呈現結果如下：

![](https://i.imgur.com/1RXP4aB.png)


**由此可知，修改 `el.value` 不等於修改 HTML 標籤的 value 屬性值**

### 統整：
* `el.value` 對應的是 input 欄位目前「輸入的值」
* `el.getAttribute('value')` 對應的是 input 標籤的「預設屬性值」
* 修改 `el.value` 並不會影響 input 標籤的 value 預設屬性，使用 `setAttribute()` 才會。

### 補充 `e.target.value`
在[前一天](https://hackmd.io/Wl1vhP5RRR-6W-p1MnI3Mg)有提到事件監聽內函式有一個參數（這邊以 e 表示），e 是一個物件，其中有一個 target 屬性為觸發事件時的元素，此時就可以直接利用 `e.target` 搭配 `.value` 來取得該表單元素觸發事件時的值。

HTML
```htmlembedded=
<select name="num" class="num">
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
</select>
```
JS
```javascript=
const num = document.querySelector('.num');
num.addEventListener('change', function(e) {
  // 當 select 選項改變時就會觸發
  // 觀察下方印出的值
  console.log(e.target);  
  console.log(e.target.value);  
  console.log(typeof(e.target.value));
});
```