# Vue.js 學習旅程Mile 10 – Event Handling 事件處理篇-2:Modifiers 修飾符 ###### tags: `w3HexSchool` `Vue` `Javascript` ## 修飾符 Modifiers 修飾符依照功能可以分為下面兩類: * 事件修飾符(Event Modifiers):事件相關的處理或設定。 * 按鍵修飾符(Key Modifiers):鍵盤或是按鈕的事件中觸發的按鍵設定。 ## 事件修飾符 (Event Modifiers) Vue 提供一些常用處理的修飾符,讓我們可以直接設定在屬性上,除了減少程式碼量外,最大的目的是讓方法盡量只是單純處理邏輯,而不用多去擔心相關的 DOM 處理。 * `.stop` : 呼叫 event.stopPropagation(),停止觸發上層 DOM 元素事件 * `.prevent` : 呼叫 event.preventDefault(),避免瀏覽器預設行為 * `.capture` : 不管觸發事件的目標是否是下層, 設定 `capture` 的事件一定會先觸發 * `.self` : 僅觸發自己範圍的事件,不包含子層 ### `.stop` 修飾符 `.stop` 修飾符會叫用 `event.stopPropagation()` ,`stopPropagation` 方法會停止事件的冒泡。 在預設的情況下,觸發了下層 DOM 元素的事件後,會往上叫用其他 DOM 元素的事件,可是當加上 `stopPropagation` 後,就只會到目前的事件為止,不會往父層觸發。 Js 預設的事件傳遞方向為向上冒泡(**event bubbling**),也就是從內到外執行。 ```htmlmixed= <div class="outer" @click="alert('outer, none-once, default')"> outer <div class="middle" target="_blank" @click="alert('middle, none-capture, default')"> middle <div class="inner" target="_blank" @click.stop="alert('inner, not trigger upper except capture')"> inner, stopPropagation(not trigger upper except capture) </div> </div> </div> ``` 當按下 inner 後, middle 跟 outer 的事件會因為 inner 的 click 加入了 `.stop` 修飾符而不被觸發。 ### `.prevent` 修飾符 `.prevent` 修飾符會叫用 `event.preventDefault()` ,`preventDefault` 會停止瀏覽器的預設行為。例如: checkbox 的勾選/取消勾選行為、 form 的 submit 送出表單行為等,都會因為 `preventDefault` 而沒有觸發。 ```htmlmixed= <a class="inner" href="https://developer.mozilla.org/" target="_blank" @click.prevent="alert('inner2, none-passive, default, not open new page')"> inner2, none-passive & preventDefault(not open new page) </a> ``` 原本按下超連結後會直接開啟 href 設定的頁面,可是因為 click 事件有設定 `.prevent` 修飾符,所以不會開啟連結。 ### `.capture` 修飾符 不管觸發事件的 DOM 元素是誰,使用 `.capture` 修飾符的事件會優先觸發。 ```htmlmixed= <div class="middle" target="_blank" @click.capture="alert('middle, capture')" @click="alert('middle, none-capture, default')"> middle, capture & none-capture & self <a class="inner1" href="https://www.mozilla.org" target="_blank" @click="alert('inner1, passive, open new page')"> inner1, passive & preventDefault(which is not allowed) </a> </div> ``` 當按下 inner1 時,可以看到 alert('middle, capture') 先被觸發,再來是 alert('inner1, passive, open new page') ,最後才是 alert('middle, none-capture, default') ,由此現象可知 `.capture` 會打破由內而外的事件傳遞規則,先行觸發。 關於捕獲與冒泡事件,可參考以下文章: * [DOM 的事件傳遞機制:捕獲與冒泡](https://blog.techbridge.cc/2017/07/15/javascript-event-propagation/) * [JavaScript Capture Bubble DOM事件獲取&冒泡](https://iandays.com/2019/03/21/eventpass/) * [Bubbling and capturing](https://javascript.info/bubbling-and-capturing) ![](https://i.imgur.com/3QSQTur.png) ### `.self` 修飾符 `.self` 修飾符只會觸發自己範圍內的事件,不包含子元素。 ```htmlmixed= <div class="middle" target="_blank" @click.self="alert('middle, self')"> middle, self <div class="inner4" target="_blank" @click="alert('inner4')"> inner4 </div> </div> ``` ### `.once` 修飾符 `.once` 修飾符使事件只會觸發一次。 ```htmlmixed= <div class="outer" @click.once="alert('outer, once')" @click="alert('outer, none-once, default')"> outer </div> ``` 當點擊第一次的時候兩個事件都會被觸發,可是之後都只有沒有 `.once` 修飾符的事件會被觸發。 ### `.passive` 修飾符 `.passive` 修飾符會無視 `event.preventDefault()` 的功能,只要加上此修飾符就一定會觸發瀏覽器的預設行為。 不要把 `.passive` 和 `.prevent` 一起使用,因為 `.prevent` 將會被忽略。 ```htmlmixed= <a class="inner1" href="https://www.mozilla.org" target="_blank" @click.passive.prevent="alert('inner1, passive, open new page')"> inner1, passive & preventDefault(which is not allowed) </a> ``` 由於 `.passive` 會使 `preventDefault` 無效,所以就算在 `.passive` 後面加上 `.prevent` 還是會開啟連結頁面。 ### 修飾符的順序 使用修飾符時,順序很重要;相應的程式碼會以同樣的順序產生。因此,用 `v-on:click.prevent.self` 會阻止所有的點擊,而 `v-on:click.self.prevent `只會阻止對元素自身的點擊。 ## 按鍵修飾符(Key Modifiers) 監聽鍵盤事件的特定鍵值。 :::warning [keyCode](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) 的事件用法已經被廢棄了並可能不會被最新的瀏覽器支持。 ::: ### 按鍵值 只要是在 [KeyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values) 上的按鍵名稱都可以用 **kebab-case** 的方式設定在修飾符上。 ```htmlmixed= <input v-on:keyup.page-down="onPageDown"> ``` Vue 會在函數中使用 $event.key === 'PageDown' 判斷式決定是否為目標按鈕 ### 按鍵碼別名 為了在必要的情況下支持舊瀏覽器,Vue 提供了絕大多數常用的按鍵碼的別名: * `.enter` * `.tab` * `.delete` (Delete 跟 Backspace 按鍵都會觸發) * `.esc` * `.space` * `.up` * `.down` * `.left` * `.right` ### 自定義按鍵修飾符別名 在 `Vue.config.KeyCodes` 物件中設定自定義的別名: * key : 別名名稱,不可使用 camelCase 設定名稱,但是可以使用雙引號綁定 kebab-case 的別名。 * value : 對應的按鍵編號,可以使用陣列同時綁定多個編號。 ```htmlmixed= <div id="app"> <input @keyup.f1="what='keyup.f1'" @keyup.up="what='keyup.up'" @keyup.insert-mode="what='keyup.insert-mode'" /> <span>You trigger event by <strong>{{what}}</strong></span> </div> ``` ```javascript= Vue.config.keyCodes = { f1: 112, // f1 up: [38, 87], // 數字鍵 8 跟 w // insertMode: 73, // won't work "insert-mode": 73 // i }; ``` ### 系統修飾鍵 (System Modifier Keys) 僅在按下相應按鍵時才觸發滑鼠或鍵盤事件的監聽器 * `.ctrl` * `.alt` * `.shift` * `.meta` ```htmlmixed= <!-- Alt + C --> <input v-on:keyup.alt.67="clear"> <!-- Ctrl + Click --> <div v-on:click.ctrl="doSomething">Do something</div> ``` #### 與常規按鍵不同之處 使用系統修飾鍵設定修飾符的 `keyup` 事件只有在該系統鍵按住的狀態下才會觸發事件,例如: ```htmlmixed= <div id="app"> <input" @keyup.ctrl="what='keyup.ctrl'" @keyup.17="what='keyup.17'" /> <span>You trigger event by <strong>{{what}}</strong></span> </div> ``` * `@keyup.ctrl` : 要在按住 Ctrl 鍵的狀況下釋放其他按紐才會觸發。 * `@keyup.17` : 只要釋放 Ctrl 按鈕就會觸發。 #### `.exact` 修飾符 設定 `.exact` 修飾符代表一定要完全符合系統修飾鍵的設定才會觸發事件 ```htmlmixed= <!-- 即使 Alt 或 Shift 被一同按下時也會觸發 --> <button v-on:click.ctrl="onClick">A</button> <!-- 有且只有 Ctrl 被按下的時候才觸發 --> <button v-on:click.ctrl.exact="onCtrlClick">A</button> <!-- 沒有任何系統修飾符被按下的時候才觸發 --> <button v-on:click.exact="onClick">A</button> ``` ### 滑鼠按鍵修飾符 (Mouse Button Modifiers) Vue 提供左中右三個滑鼠按鍵的修飾符 * `.left` * `.right` * `.middle` ## 參考資料 * [Vue.js - Event Handling](https://vuejs.org/v2/guide/events.html) * [Vue.js - v-on](https://cn.vuejs.org/v2/api/index.html#v-on) * [Vue.js Core 30天屠龍記(第17天): `v-on` 的修飾符 Part 1 - 事件修飾符](https://ithelp.ithome.com.tw/articles/10206828) * [Vue.js Core 30天屠龍記(第18天): `v-on` 的修飾符 Part 2 - 按鍵修飾符](https://ithelp.ithome.com.tw/articles/10207356) * [Day10 - [Directives] 事件處理(Event Handling)](https://ithelp.ithome.com.tw/articles/10194631) * [用範例理解 Vue.js #12:Event Handling(v-on)](https://ithelp.ithome.com.tw/articles/10192961) * [Vue.js: Methods 與事件處理 (Event Handling)](https://cythilya.github.io/2017/04/17/vue-methods-and-event-handling/) * [MDN-EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters)