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 來確定事件是不是由於冒泡而觸發的。經常用於事件冒泡時處理事件委託。