---
# System prepended metadata

title: '第 25 節： The Missing Piece: DOM Events'
tags: [The Web Developer Bootcamp 2021, JavaScript, Udemy]

---

Udemy課程：[The Web Developer Bootcamp 2021（Colt Steele）](https://www.udemy.com/course/the-web-developer-bootcamp/)
# 第 25 節： The Missing Piece: DOM Events
###### tags: `JavaScript` `Udemy` `The Web Developer Bootcamp 2021`
2021.04.08（Thu.）~04.11(Sun.)
## ● 上課筆記
## Event
Event就是回應使用者的輸入或者是動作。例如說：clicking、dragging、dropping、hovering、scrolling、submitting a form、pressing a key、moving the mouse wheel、double clicking、copying、pasting on their clipboard、resizing the screen等等的動作都稱作Event。

## 1. Inline Event & The onclick property
先以onclick為例，若想使用onclick這個event，可以有兩種方法，一種是將onclick寫在html裡面，第二種則是另外寫在JavaScript裡面。

* 第一種
直接加在html的button標籤之上，也就是所謂inline event。
```htmlmixed=
//Html
<body>
    <button onclick="console.log('You clicked me!')">
    button1
    </button>
</body>
```
* 第二種
另外利用JavaScript來將onclick這個event做成一個function
```htmlmixed=
//Html
<body>
    <button id="btn2">
    button2
    </button>
</body>
```
```javascript=
//JavaScript
var btn2 = document.querySelector("#btn2")

btn2.onclick = function(){
    console.log = ("You clicked me!")
}
```

**onmouseenter**
鼠標只要碰到目標物，就會產生反應。底下範例，即是當屬表碰到id為btn2的button，就會印出"Don't touch me!"
```htmlmixed=
//Html
<body>
    <button id="btn2">
    button2
    </button>
</body>
```
```javascript=
btn2.onmouseenter = function(){
    console.log("Don't touch me!")
}
```

## 2. addEventListener(eventType, listener)
> 參考網址：[JavaScript DOM Event (事件處理)](https://www.fooish.com/javascript/dom/event.html)

addEventListener這個用法可以用來綁定元素的事件處理函數，第一個參數eventType是[事件名稱](https://developer.mozilla.org/zh-CN/docs/Web/Events)，例如click、mouseenter等等。第二個參數listener則是事件處理函數，就例如說我接收到了click這個事件，那我要給予甚麼動作，這就是listener在做的。

例如底下這個範例，就是當click這個事件在button上發生了（也就是使用者點擊了），那麼就會跑出警告窗"You clicked me!"
```javascript=
const button = document.querySelector("h1")

button.addEventListener = ("click", ()=>{
    alert("You clicked me!")
})
```

如果有兩個事件要同時發生在同一個物件上的話，就一定得用addEventListener。

若是沒用addEventListener的話，如下方法，就只會讓一件事情發生，底下範例則只會使shout()發生而已，就有點像css中，你先設了color為purple，又再下設color為red，那底下的就會蓋住上方的，也就會顯示出紅色而已。
```htmlmixed=
<button id="tas">
NEW button
</button>
```
```javascript=
function twist(){
    console.log("TWIST!")
}
function shout(){
    console.log("SHOUT!")
}

const tasButton = document.querySelector("#tas")
tasButton.onclick = twist
tasButton.onclick = shout
```
所以如果想讓twist跟shout都能作用的話，作法如下：
```javascript=
tasButton.addEventListener = ("onclick", twist)
tasButton.addEventListener = ("onclick", shout)
```

## 3. Keyboard Events & Event Objects
**keydown**
當使用者對鍵盤按下任意鍵，即是觸發keydown。

**keyup**
反之，如果手一從按鍵離開，即是觸發了keyup。

雖然上面兩者可以知道是否按了按鍵，或是否停止按按鍵，但對於按了甚麼無從得知，因此如果想知道按了甚麼按鍵，就必須使用到event object。

* 範例：
以下面程式碼為例，假如我現在按了a，則此程式碼會印出兩行，第一行為"a"，第二行為"keyA"；假如我按了空白鍵，則第一行為" "(沒東西)，第二行則是"Space"；假如我按了左邊的"shift"，則第一行為"Shift"，第二行為"ShiftLeft"。
```javascript=
input.addEventListener("keydown", function(e){
    console.log(e.key)
    console.log(e.code)
})
```

## 4. Form Events & PreventDefault
**submit**
submit 事件會在表單送出時觸發。要注意的是，submit 事件只會在 form element 上觸發， button 或是 submit input 則不會觸發。（送出的是「表單」，而非「按鈕」）

**preventDedault**
如果事件可以被取消，就取消事件（即取消事件的預設行為）。但不會影響事件的傳遞，事件仍會繼續傳遞。

就例如說有個連結可以按，但是你不希望他被點了就跳頁（被點就跳頁是DOM的預設），所以說若希望點了，有執行事件的過程，但卻不希望跳頁的話，就可以使用event.preventDefault()即可。

```javascript=
tweetForm.addEventListener('submit', function (e) {
    e.preventDefault();
})
```

## 5. Input & Change Events
**input event**
當一個 `<input>`, `<select>`, 或 `<textarea>` 元素的 value 被修改時，就會觸發 input 事件。
```javascript=
const input = document.querySelector("input")
const h1 = document.querySelector("h1")

input.addEventListener("input", function(e){
    h1.innerText = input.value
})
```

**change event**
當使用者更改`<input>`、`<select>`和`<textarea>` 元素的值並提交這個更改時，change 事件在這些元素上觸發。

和 input 事件不一樣，change 事件並不是每次元素的 value 改變時都會觸發。

## 6. Event Bubbling
> 參考網址：
> [[教學] 瀏覽器事件：Event Bubbling, Event Capturing 及 Event Delegation](https://shubo.io/event-bubbling-event-capturing-event-delegation/)

Event Bubbling指的是當某個事件發生在某個DOM element上（如：點擊），這個事件會觸發DOM elemtn的event handler，接下來會再觸發他的parent的event handler，以及parent的parent的event handler…直到最上層。

以下的例子中，點擊p會依序觸發p -> div -> form的onclick handler。

```htmlmixed=
<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p onclick="alert('p')">P
    </p>
  </div>
</form>
```
解決方法可以利用"event.stopPropagation()"，可以跟第4點的preventDedault做比較。
> 參考網址：[[筆記][JavaScript]所謂的「停止事件」到底是怎麼一回事？](https://ithelp.ithome.com.tw/articles/10198999)

## 7. Event Delegation
> 可參考網址：[為什麼有時你應該優先考慮 event delegate 而不是 event binding](https://ithelp.ithome.com.tw/articles/10120565)

先用html架出一個列表清單
```htmlmixed=
<ul id="tweets">
    <li>I AM LI!!!</li>
    <li>I AM LI!!!</li>
    <p>aslkdjaslkdjaksl</p>
</ul>
```
**接著先來看第一種想移除清單其中一條的方法：**
會發現說，原先清單就有的兩行I AM LI!!!是可以移除掉的，但當我後來透過網頁input輸入的清單，便無法移除了。所以這種方法僅能移除網頁原先就存在的元素，但後來對網頁做輸入（或者任何的events，也就是使用者對畫面元素做了愗些動作）而得到的新元素，就不能做監聽，也就無法移除（或者說無法觸發remove()）了。（這是因為新增的那些元素沒有被綁定）
```javascript=
const lis = document.querySelectorAll("li")
for(let li of lis){
    li.addEventListener("click", function(){
        li.remove
    })
}
```
**於是，我們得用第二種方法才行：**
利用e.target()
```javascript=
tweetsContainer.addEventListener('click', function (e) {
    e.target.nodeName === 'LI' && e.target.remove();
})
```

**e.target()**
target 屬性可以是註冊事件時的元素，或者它的子元素。通常用於比較 event.target 和 this 來確定事件是不是由於冒泡而觸發的。經常用於事件冒泡時處理事件委託。