---
title: DOM 擷取網頁元素
tags: DOM,
description:
---
DOM(Document Object Model)
===
### 為什麼JavaScript檔案要放在``<body>``的結尾
- 因為要等``HTML``渲染完成後,``JavaScript``才能對畫面去做控制。
- 若``JavaScript``先執行,但``HTML``**尚未渲染完成**,選擇器無法對DOM做控制。

---
<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>`;
```

<br>
- **.textContent**:只有呈現文字部分
```javascript=
// HTML
<div class="div"></div>
// JavaScript
const el = document.querySelector('.div');
el.innerHTML = `<h1>標題</h1>`;
```


---
<br>
### textContent 可以跟變數混合使用
- **HTML**
```htmlembedded=
<div class="targetClass"></div>
```
- **JavaScript**
```javascript=
const targetClass = document.querySelector(".targetClass");
let score = 100;
targetClass.textContent = `<p>小華的成績為 ${score} 分</p>`;
```
結果:
(網頁渲染出的畫面)

(修改後的 HTML 結構)

---
<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節點資料。

- 因為取得的是==陣列==形式的多個``<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``的資料結構,第一層是陣列,第二層是物件。

- 第二層的物件屬性``length``,可以看見select表單內全部的``option``的資料長度。

- 第二層的物件屬性0是第一個option內容,用``[0]``或``['0']``取屬性內容,再進去一層用.value取select表單``option``值。
- 第二層的物件屬性1是第二個option內容,用``[1]``或``['1']``取屬性內容,再進去一層用.value取select表單``option``值。

```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 中觀察到以下結果:

> `.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));
})
```
結果:

<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 結果:

看到這邊,同學是不是認為 `<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 欄位「輸入的值」的確已經被更改為 "任意填入的值"

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

**由此可知,修改 `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));
});
```