Udemy課程:[The Web Developer Bootcamp 2021(Colt Steele)](https://www.udemy.com/course/the-web-developer-bootcamp/)
# 第 24 節: Introducing The World Of The DOM
###### tags: `JavaScript` `Udemy` `The Web Developer Bootcamp 2021`
2021.03.17(Wed.)~04.08(Thu.)
## ● 上課筆記
## DOM
> D:DOCUMENT 文件
> O:OBJECT 物件
> M:MODEL 模型
先看看MDN是如何解釋DOM的:
**文件物件模型(Document Object Model, DOM)** 是 HTML、XML 和 SVG 文件的程式介面。它提供了一個文件(樹)的結構化表示法,並定義讓程式可以存取並改變文件架構、風格和內容的方法。DOM 提供了文件以擁有屬性與函式的節點與物件組成的結構化表示。節點也可以附加事件處理程序,一旦觸發事件就會執行處理程序。 本質上,它將網頁與腳本或程式語言連結在一起。
雖然常常使用 JavaScript 來存取 DOM,但它本身並不是 JavaScript 語言的一部分,而且它也可以被其他語言存取(雖然不太常見就是了)。
其他詳細內容可參考:[深入理解網頁架構:DOM](https://ithelp.ithome.com.tw/articles/10202689)
****
## DOM操作語法
> 參考資料:[DOM概念](https://ithelp.ithome.com.tw/articles/10094965)
> 覺得這邊有個要注意的點,就是element後面要不要加s(是單數還是複數)
****
## 1. getElementById()
Document的方法 getElementById()返回一個匹配特定 ID的元素. 由於元素的 ID 在大部分情況下要求是獨一無二的,這個方法自然而然地成為了一個高效查找特定元素的方法。
* 範例:
```javascript=
var choose = document.getElementById("choose")
//可以取出 HTML 內容當中 <div id=”choose”> test </div> 當中的 test 字串
```
## 2. getElementsByTagName()
返回的 HTML集合是動態的, 意味著它可以自動更新自己來保持和 DOM 樹的同步而不用再次調用 document.getElementsByTagName() 。
* 用法:
```javascript=
document.getElementsByTagName("標籤名稱")
```
* 範例:
```javascript=
document.getElementsByTagName("p")
//會回傳文件當中的所有 <p> 元素內之內容
```
## 3. getElementsByClassName()
當呼叫 document 物件時,它會搜尋整個文件,包括根節點在內。你也可以在所有元素呼叫 getElementsByClassName(),那它就只會回傳含有給定 class 的特定根元素的後代元素。
## 4. querySelector / querySelectorAll
**querySelector**
回傳 document 第一個符合特定選擇器群組的元素(採用深度優先,前序追蹤 document 節點)。
* 範例:
```javascript=
document.querySelector("p")
//會回傳文件當中的所有 <p> 元素內之內容
```
可參考網址:[JavaScript 基礎知識-querySelector](https://ithelp.ithome.com.tw/articles/10211605)
**querySelectorAll**
至於querySelectedAll的話,差別就在於querySelector他採用深度優先,前序追蹤 document 節點,所以假如我抓"p"的話,只會抓到最前面的第一個p,因此querySelectedAll顧名思義就是我抓"p",所有的p都會被我抓出來。
另外querySelectorAll抓到全部後,會存成一個陣列,所以想要利用他時,要用陣列的方式取得。
* 範例:
html的部分:
```htmlmixed=
<h2 class="title">1</h2>
<h2 class="title">2</h2>
<h2 class="title">3</h2>
<h2 class="title">4</h2>
```
JavaScript的部分:
```javascript=
var allTitle = document.querySelectorAll("title")
console.log(allTitle[0]) //1
console.log(allTitle[1]) //2
console.log(allTitle[2]) //3
console.log(allTitle[3]) //4
//要全部都取得,就要用陣列的方法:for迴圈
for(var i = 0; i < allTitle.length; i++){
console.log(allTitle[i])
}
//1,2,3,4
```
****
```
元素類型:
1. 標籤元素
2. class元素
3. id元素
```
**當選取class元素 -> 用點點(.)**
```javascript=
document.querySelector(".title")
```
**當選取id元素 -> 用井字號(#)**
```javascript=
document.querySelector("#title")
```
## 5. innerHTML / textContent / innerText
**innerHTML**
innerHTML設定或獲取標籤所包含的HTML 文字資訊(從標籤起始位置到終止位置全部內容,包括HTML標籤,但不包括自身)
1. 他會顯示所有標籤
**textContent**
textContent屬性表示了節點或其後代的文字內容。
1. 假設在css設定display:none,用textContent仍看得到
**innerText**
innerText設定或獲取標籤所包含的文字資訊(從標籤起始位置到終止位置的內容,去除HTML標籤,但不包括自身)
1. 假設在css設定display:none,用innerText會看不到
2. 只能單純改文字,如果想新增或更改新標籤,就要用innerHTML
## 6. classList
可參考網址:[JS基礎篇–HTML DOM classList 屬性](https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/27430/)
頁面DOM裡的每個節點上都有一個classList物件,程式設計師可以使用裡面的方法新增、刪除、修改節點上的CSS類。
**add**
新增class = "purple"(css中已經有設置名為purple的class)到h2上面
之後再新增class = "border"(css中已經有設置名為border的class)
```javascript=
h2.classList.add("purple")
h2.classList.add("border")
```
另一種方法:
```javascript=
h2.addClass("purple")
h2.addClass("border")
```
**remove**
有新增的功能,相對地一定有移除功能!
```javascript=
h2.classList.remove("border")
```
另一種方法:
```javascript=
h2.removeClass("border")
```
**contains**
contains這個用在你想確定那個class是否有存在?
例如說,我上面remove掉border這個class了,並且沒有其他border存在h2裡面,但我還是想做確認(可能class太多沒辦法馬上看出來之類的),就可以用contains。
```javascript=
h2.classList.contains("border")
//若回傳False則表示不存在
//若回傳True則表示還存在著
```
**toggle**
這個用處就是狀態交換,例如原本存在,用了toggle之後就會不存在;相反地原本若不存在,利用了toggle就會變成存在的。
(用在ckeck list、todo list、狀態來回變換的東西上很好用)
```javascript=
//假如purple這個class原本存在
h2.classList.toggle("purple") //false
//purple不存在了
h2.classList.toggle("purple") //true
//purple又存在了
```
****
classList這裡抓元素時前面不需要點點(.)的原因,放上之前在Hahow提問過,得到的回答:

## 7. Traversing Parent / Child / Sibling
**parentElement**
當前節點的父元素,此處b的父元素就是p
```htmlmixed=
<p>
<b>Silkie</b>
</p>
```
```javascript=
const firstBold = document.querySector("b")
console.log(firstBold) //<b>Silkie</b>
console.log(firstBold.parentElement) //<p>...</p>
```
**children**
當前節點的子元素,可能會有多個,此處p的children就有b,b,a,a
```htmlmixed=
<p>
<b>Silkie1</b>
<b>Silkie2</b>
<a>link1</a>
<a>link2</a>
</p>
```
```javascript=
var paragraph = firstBold.parentElement
paragraph.children //[b,b,a,a]
paragraph.children[0] //<b>Silkie1</b>
paragraph.children[1] //<b>Silkie2</b>
paragraph.children[2] //<a>link1</a>
paragraph.children[3] //<a>link2</a>
```
****
先來個html的部分:
```htmlmixed=
<p>
<b id="b1">Silkie1</b>
<b id="b2">Silkie2</b>
<a id="a1">link1</a>
<a id="a2">link2</a>
</p>
```
**previousSibling**
可以得到當前節點的前一個兄弟節點,如果沒有則回傳null
```javascript=
const b1 = document.getElementById("b1")
const a2 = document.getElemnetById("a2")
b1.previousSibling //null
a2.previousSibling //<a id="a1">link1</a>
```
**nextSibling**
可以得到當前節點緊跟在後的兄弟節點,如果沒有則回傳null
```javascript=
const b1 = document.getElementById("b1")
const a2 = document.getElemnetById("a2")
b1.nextSibling //<b id="b2">Silkie2</b>
a2.nextSibling //null
```
## 8. Append / AppendChild
```javascript=
const parent = document.createElement("div")
const child = document.createElement("p")
const child2 = document.createElement("p")
//插入節點Node物件
parent.append(child) //<div><p></p></div>
parent.appendChild(child) //<div><p></p></div>
//插入DOMString
parent.append("文字") //<div>文字</div>
parent.appendChild("文字") //會出現錯誤
//返回值
var appendValue = parent.append(child)
var appendChildValue = parent.appendChild(child)
console.log(appendValue) //undefined
console.log(appendChildValue) //<p></p>
//新增專案數量
parent.append(child, child2, "Hello World") //正常
parent.appendChild(child, child2, "Hello World") //也正常,但只新增第一個元素,而忽略其他元素
```
* 總整理:
| | append() | appendChild() |
| ---- | -------- | ------------- |
|插入節點Node物件|接受|接受|
|插入DOMString|接受|不接受|
|返回值|沒有返回值|返回附加的Node物件|
|新增專案數量|允許新增多個|允許新增單個|
## 9. removeChild / remove
```javascript=
const img = document.querySelector("img")
//以下兩種寫法結果是一樣的,都可以把這張img給移除掉
img.remove()
img.parentElement.removeChild(img)
```