開始用 JS 操作網頁
走到這裡,你已經學會了 JS 的基本語法、ES6 的新特性,接下來我們要開始進入 JS 的進階部分,也就是如何用 JS 操作網頁。
我們都知道,網頁是由 HTML、CSS 和 JavaScript 三種語言組成的,他們的分工如下:
| 語言 | 負責內容 |
|---|---|
| HTML | 結構、屬性、內容 |
| CSS | 外觀、樣式 |
| JS | 行為、互動 |
而操作網頁最重要的一個部分就是 DOM。
DOM
DOM(Document Object Model)是描述整個網頁結構的 JS 物件,我們可以透過 JS 操作 DOM 來改變網頁的內容、屬性、樣式、元素等等。
常見的 DOM 的結構如下(這只是個範例不是一定長這樣):
document
├── html
│ ├── head
│ │ ├── title
│ │ └── meta
│ └── body
│ ├── header
│ │ ├── h1
│ │ └── nav
│ ├── main
│ │ ├── article
│ │ └── aside
│ └── footer
│ └── p拿 header 這個元素來說,在 document 裡的每一個元素可以被叫做 element。 而且如果將 document 轉 90 度,你會發現它長得很像一棵樹,所以我們可以將 document 稱為 DOM 樹;樹上的每一個 element 都可以被稱為節點(node)。

操作 DOM
我們先假設有一個 HTML 檔案如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root">
<h1 class="my-h1">Hello, World!</h1>
</div>
<div id="app">
<div>test1</div>
<div>test2</div>
<div>test3</div>
</div>
<script src="/src/index.js"></script>
</body>
</html>取得元素
如果要找到 id="root" 的元素,可以這樣寫:
let root = document.getElementById('root')如果要找到 class="my-h1" 的元素,並修改文本、並將字體顏色改成紅色,可以這樣寫:
let myH1 = document.getElementsByClassName('my-h1')[0]之所以要用 [0] 來取得第一個元素,是因為 class 是允許複數使用的,所以 getElementsByClassName 會回傳一個陣列,我們要取得第一個元素就要用 [0];但是 id 是唯一的,所以 getElementById 會直接回傳該元素。
如果要找到 id=root 下的 h1 元素,可以這樣寫:
let divs = document.querySelector('#root h1')要注意的是 querySelector 只會回傳第一個符合的元素,如果要取得所有符合的元素,可以使用 querySelectorAll。
如果要找到 id=app 下的所有 div 元素,可以這樣寫:
let divs = document.querySelectorAll('#app div')由於用的是 querySelectorAll,所以會回傳一個陣列。
如果要用 querySelector 找到 class=my-h1 的元素,可以這樣寫:
let myH1 = document.querySelector('.my-h1')總之,querySelector 和 querySelectorAll 可以用節點樹的上下階層關係來找到元素。 id 用 # 來表示,class 用 . 來表示,例如上述的 #root 或是 .my-h1。
修改元素
如果要修改元素的內容,可以這樣寫:
let myH1 = document.querySelector('.my-h1')
myH1.textContent = 'Hello, JavaScript!' // 修改元素的文本內容
myH1.style.color = 'red' // 修改元素的字體顏色
myH1.style = {color: 'red', fontSize: '24px'} // 也可以用物件的方式來修改元素的樣式
myH1.setAttribute('id', 'unique-h1') // 將元素的 id 設為 unique-h1
myH1.classList.add('new-class') // 為元素新增一個 class=new-class
myH1.classList.remove('new-class') // 移除元素的 class=my-h1INFO
可以透過 textContent 來修改元素的文本內容,透過 style 來修改元素的樣式,透過 setAttribute 來修改元素的屬性,透過 classList 來修改元素的 class。還有很多其他的方法可以用來修改元素,這裡只列出一些常見的。更多的可以參考 MDN。
新增元素
如果要在 id=root 的 div 底下新增一個 h2 元素,可以這樣寫:
let newH2 = document.createElement('h2')
newH2.textContent = 'This is a H2, created by JS!'
const root = document.getElementById('root')
root.appendChild(newH2) // 在 root 的最後面新增一個 h2 元素,以這個範例來說會在 h1 的下面新增一個 h2
const newParagraph = document.createElement('p')
newParagraph.textContent = 'This is a paragraph, created by JS!'
root.insertBefore(newParagraph, newH2) // 在 newH2 的前面新增一個 p 元素甚至你可以搭配陣列操作來為每個 #app 底下的每個 div 元素新增一個 p 元素:
const divs = document.querySelectorAll('#app div')
divs.forEach((node, index)=> {
const newP = document.createElement('p')
newP.textContent = `This is a paragraph ${index}, created by JS!`
node.appendChild(newP)
})刪除元素
如果要刪除 .my-h1 元素,可以這樣寫:
let myH1 = document.querySelector('.my-h1')
myH1.remove()不過要注意的是,如果要刪除的元素有子節點,那麼它的子節點也會被一併刪除。
let root = document.getElementById('root')
root.remove() // 這樣會把 root 底下的所有元素都刪除事件
如果要為 .my-h1 元素新增一個點擊事件,可以這樣寫:
let myH1 = document.querySelector('.my-h1')
// 對 myH1 加入一個 click 的事件監聽器
myH1.addEventListener('click', function() {
myH1.textContent = 'You clicked me!'
myH1.style.color = 'blue'
})
// 或是直接對 myH1 的 onClick 事件進行設定
myH1.onclick = function() {
myH1.textContent = 'You clicked me!'
myH1.style.color = 'blue'
}INFO
事件的種類有很多,例如 click、mouseover、mouseout、keydown、keyup 等等,可以參考 MDN。
BOM
BOM(Browser Object Model)是描述瀏覽器的 JS 物件,瀏覽器的所有核心功能都在這,像是視窗、歷史、定時器、瀏覽器的屬性等等。
最簡單取得 BOM 物件的方式就是
console.log(window)而 window 常見的屬性有:
| 屬性 | 說明 |
|---|---|
| window.innerHeight | 視窗的高度 |
| window.innerWidth | 視窗的寬度 |
| window.location | 瀏覽器的 URL |
| window.navigator | 瀏覽器的資訊 |
| window.document | 瀏覽器的 DOM |
| window.history | 瀏覽歷史 |
| window.localStorage | 本地儲存 |
| window.sessionStorage | 會話儲存 |
| window.alert() | 警告視窗 |
| window.confirm() | 確認視窗 |
| window.prompt() | 提示視窗 |
| window.setTimeout() | 設定定時器 |
| window.setInterval() | 設定間隔定時器 |
| window.clearTimeout() | 清除定時器 |
| window.clearInterval() | 清除間隔定時器 |
| window.open() | 開啟新視窗 |
| window.close() | 關閉視窗 |
你會發現,window 有很多屬性和方法,這些都是 BOM 的一部分,我們可以透過這些屬性和方法來操作瀏覽器。 而且上述花了很多篇章介紹的 DOM 也是掛載在 window 上的一個屬性,所以我們可以透過 window.document 來操作 DOM。
總結
我們學習了何為 DOM 和 BOM,以及如何透過 JS 來操作網頁和瀏覽器。 事實上在現代的前端開發中,我們很少直接操作 DOM,而是透過如 React、Vue、Angular這樣的前端函式庫、框架來操作 DOM,但是其實這些工具的底層邏輯還是透過 JS 來操作 DOM 的,只是它們幫我們封裝了很多操作 DOM 的細節,讓我們可以更專注在業務邏輯上。
