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