Skip to content

開始用 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 Tree

操作 DOM

我們先假設有一個 HTML 檔案如下:

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" 的元素,可以這樣寫:

javascript
let root = document.getElementById('root')

如果要找到 class="my-h1" 的元素,並修改文本、並將字體顏色改成紅色,可以這樣寫:

javascript
let myH1 = document.getElementsByClassName('my-h1')[0]

之所以要用 [0] 來取得第一個元素,是因為 class 是允許複數使用的,所以 getElementsByClassName 會回傳一個陣列,我們要取得第一個元素就要用 [0];但是 id 是唯一的,所以 getElementById 會直接回傳該元素。

如果要找到 id=root 下的 h1 元素,可以這樣寫:

javascript
let divs = document.querySelector('#root h1')

要注意的是 querySelector 只會回傳第一個符合的元素,如果要取得所有符合的元素,可以使用 querySelectorAll

如果要找到 id=app 下的所有 div 元素,可以這樣寫:

javascript
let divs = document.querySelectorAll('#app div')

由於用的是 querySelectorAll,所以會回傳一個陣列。

如果要用 querySelector 找到 class=my-h1 的元素,可以這樣寫:

javascript
let myH1 = document.querySelector('.my-h1')

總之,querySelectorquerySelectorAll 可以用節點樹的上下階層關係來找到元素。 id# 來表示,class. 來表示,例如上述的 #root 或是 .my-h1

修改元素

如果要修改元素的內容,可以這樣寫:

javascript
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-h1

INFO

可以透過 textContent 來修改元素的文本內容,透過 style 來修改元素的樣式,透過 setAttribute 來修改元素的屬性,透過 classList 來修改元素的 class。還有很多其他的方法可以用來修改元素,這裡只列出一些常見的。更多的可以參考 MDN

新增元素

如果要在 id=root 的 div 底下新增一個 h2 元素,可以這樣寫:

javascript
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 元素:

javascript
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 元素,可以這樣寫:

javascript
let myH1 = document.querySelector('.my-h1')
myH1.remove()

不過要注意的是,如果要刪除的元素有子節點,那麼它的子節點也會被一併刪除。

javascript
let root = document.getElementById('root')
root.remove() // 這樣會把 root 底下的所有元素都刪除

事件

如果要為 .my-h1 元素新增一個點擊事件,可以這樣寫:

javascript
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

事件的種類有很多,例如 clickmouseovermouseoutkeydownkeyup 等等,可以參考 MDN

BOM

BOM(Browser Object Model)是描述瀏覽器的 JS 物件,瀏覽器的所有核心功能都在這,像是視窗、歷史、定時器、瀏覽器的屬性等等。

最簡單取得 BOM 物件的方式就是

javascript
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 的細節,讓我們可以更專注在業務邏輯上。

Wrirten by Aaron Su