# v-on
的修飾符 Part 1 - 事件修飾符
講解事件時有提到 v-on
所綁定的事件後面可以以點( .
)來區隔事件及修飾符,像是 @click.prevent
中 click
是事件,而 prevent
就是修飾符,表示會避免原本預設的行為。
# 修飾符
修飾符依照功能可以大概分為下面兩類:
- 事件修飾符: 事件相關的處理或設定。
- 按鍵修飾符: 鍵盤或是按鈕的事件中觸發的按鍵設定。
今天講解的是事件修飾符。
# 事件修飾符
在事件中,我們常常需要叫用像是 event.preventDefault()
或 event.stopPropagation()
這類的處理, Vue.js 提供給我們一些常用處理的修飾符,讓我們可以直接設定在屬性上,除了減少代碼量外,最大的目的是讓方法盡量只是單純處理邏輯,而不用多去擔心相關的 DOM 處理。
Vue.js 提供的事件修飾符有下面這幾個:
.stop
: 停止觸發上層 DOM 元素事件。.prevent
: 避免瀏覽器預設行為。.capture
: 不管觸發事件的目標是否是下層, 設定capture
的事件一定會先觸發。.self
: 只有觸發此 DOM 元素本身才會觸發self
事件。.once
: 此事件只觸發一次。.passive
: 無視prevent
功能。
# 本文範例
本文範例是 Vue.js 版本的 MDN - EventTarget.addEventListener() 的 Example of options usage (opens new window) ,並補齊 Vue.js 相關的修飾符例子,所以本文每個修飾符的範例都會是這個範例的子集,而 css 及 js 在這章比較不重要的就不再重貼,我們會聚焦在 Vue 模板的設定上。
# .stop
修飾符
.stop
修飾符會叫用 event.stopPropagation()
,stopPropagation
方法會停止事件的冒泡。
在預設的情況下,觸發了下層 DOM 元素的事件後,會往上叫用其他 DOM 元素的事件,可是當加上 stopPropagation
後,就只會到目前的事件為止,不會往上層觸發。
下例可以說明此情況:
<div class="outer" @click="alert('outer, none-once, default')">
outer
<div class="middle" target="_blank" @click="alert('middle, none-capture, default')">
middle
<div class="inner3" target="_blank" @click.stop="alert('inner3, not trigger upper except capture')">
inner3, stopPropagation(not trigger upper except capture)
</div>
</div>
</div>
當按下 inner3
後, middle
跟 outer
的事件會因為 inner3
的 click
加入了 .stop
修飾符而不被觸發。
# .prevent
修飾符
.prevent
修飾符會叫用 event.preventDefault()
,preventDefault
會停止瀏覽器的預設行為,像是 checkbox
的勾選/取消勾選行為、 form
的 submit
送出表單行為都會因為 preventDefault
而沒有觸發。
以下面的 <a>
標籤做說明:
<a class="inner2" 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
修飾符的事件會優先觸發。
我們來看下面的例子:
<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
會打破由內而外的事件傳遞規則,先行觸發。
# .self
修飾符
.self
修飾符使事件的觸發限制在只有自己觸發的時候在會叫用,由其他元素所觸發的事件都不會叫用此方法。
<div class="middle" target="_blank" @click.self="alert('middle, self')">
middle, self
<div class="inner4" target="_blank" @click="alert('inner4')">
inner4
</div>
</div>
如果按下 inner4
則只會觸發 inner4
的點擊事件,而 middle
因為 .self
修飾符的關係只有在點擊 middle
自己時才會觸發。
# 修飾符的順序
在設定修飾符時要注意排序,排序在前的修飾符會先被建立,因此觸發的效果也會有先後,以 prevent
跟 self
為例:
<a class="inner4" href="https://developer.mozilla.org/" target="_blank" @click.prevent.self="alert('inner4, prevent then self, not open new page')">
inner4, prevent then self
<div class="deepest">
click me would not open new page
</div>
</a>
<a class="inner5" href="https://developer.mozilla.org/" target="_blank" @click.self.prevent="alert('inner5, self then prevent, not open new page')">
inner5, self then prevent
<div class="deepest">
click me would open new page
</div>
</a>
inner4
是先prevent
再self
,而inner5
是先self
再prevent
,當你按下click me would not open new page
時,事件會往上傳遞。- 在
inner4
時的click
事件會先執行prevent
阻止瀏覽器的預設行為,所以不會開啟連結頁面,之後會執行self
判斷觸發者是否為自己,發現不是後,不會觸發事件。 - 在
inner5
時的click
事件會先執行self
判斷觸發者是否為自己,發現不是後,直接結束事件,所以不會執行prevent
,因此會開啟連結頁面。
- 在
# .once
修飾符
.once
修飾符使事件只會觸發一次。
如下例所示:
<div class="outer" @click.once="alert('outer, once')" @click="alert('outer, none-once, default')">
outer
</div>
outer
上有兩個事件,一個有使用 once
修飾符,另一個沒有。
當點擊第一次的時候兩個事件都會被觸發,可是之後都只有沒有 once
修飾符的事件會被觸發。
# .passive
修飾符
.passive
修飾符會無視 event.preventDefault()
的功能,因此只要加上此修飾符就一定會觸發瀏覽器的預設行為。
如下例所示:
<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
還是會開啟連結頁面。
# 小結
本文依序介紹 .stop
、 .prevent
、 .capture
、 .self
、 .once
、 .passive
,每個都有不同的功能及使用情境,搭配範例演繹各個功能。
下一篇會介紹按鍵修飾符。
# 參考資料
- Vue.js Guide: Event Handling (opens new window)
- Vue.js API: v-on (opens new window)
- MDN - addEventListener (opens new window)
- MDN - stopPropagation (opens new window)
- MDN - preventDefault (opens new window)
- MDN - Example 5: Event_Propagation (opens new window)
- Harry's Tech World: [jQuery] event.preventDefault() 與 event.stopPropagation() 的差異 (opens new window)
- vue事件处理:@click.prevent.self和@click.self.prevent区别 (opens new window)