在事件處理程序中調用 event.preventDefault() 或 event.stopPropagation() 是非常常見的需求。盡管我們可以在方法中輕松實現(xiàn)這點,但更好的方式是:方法只有純粹的數(shù)據(jù)邏輯,而不是去處理 DOM 事件細節(jié)。
為了解決這個問題,Vue.js 為 v-on 提供了事件修飾符。修飾符是由點(.)開頭的指令后綴來表示的:
修飾符包括
- .stop 阻止單擊事件繼續(xù)傳播
- .prevent 取消自身的默認操作,執(zhí)行自定義方法
- .capture 添加事件監(jiān)聽器時使用事件捕獲模式,即元素自身觸發(fā)的事件先在此處理,然后才交由內(nèi)部元素進行處理
- .self 只當在 event.target 是當前元素自身時觸發(fā)處理函數(shù) 即事件不是從內(nèi)部元素觸發(fā)的
- .once 點擊事件將只會觸發(fā)一次
- .passive 滾動事件的默認行為 (即滾動行為) 將會立即觸發(fā) 而不會等待 事件方法執(zhí)行 完成,這其中包含
event.preventDefault()的情況
用事實說話:
.stop
我們接著上面的例子添加一個yanshi.vue組件
<template>
<div @click="ccTick">
<div @click="bbTick">
<button @click="aaTick">點擊一下</button>
</div>
</div>
</template>
<script>
export default {
name:"eventXiushi",
methods:{
aaTick(){
console.log("觸發(fā)了button點擊事件");
},
bbTick(){
console.log("觸發(fā)了二層div點擊事件");
},
ccTick(){
console.log("觸發(fā)了最外層div點擊事件");
},
}
}
</script>
我們的模板里的button按鈕外面包裹著兩層div,而且三者都有監(jiān)聽點擊事件,那么我們點擊按鈕的時候會怎樣呢?:

可以看出來點擊按鈕后三者都觸發(fā)了點擊事件,而且觸發(fā)順序是由里到外冒泡觸發(fā),很多時候我們肯定是不需要在一個按鈕上觸發(fā)其他的點擊事件的,(當然流氓網(wǎng)頁除外)原生的JS給我們提供了一些方法來解決如:
event.stopPropagation(); 即我們可以這樣:用特殊變量
$event把它傳入方法
<button @click="aaTick($event)">點擊一下</button>
aaTick(event){
console.log("觸發(fā)了button點擊事件");
event.stopPropagation();
}
通過event對象的stopPropagation()方法組織冒泡產(chǎn)生

當然這樣的解決方案是很不優(yōu)雅的,vue給我們封裝了修飾符來應對這種情況:
<button @click.stop="aaTick">點擊一下</button>
效果一樣

.prevent
<a href="http://localhost:8080/#/">跳轉到主頁</a>
我們增加一個<a>標簽,讓它點擊觸發(fā)的時候跳轉到歡迎主頁面
但是我們不想讓他跳轉,我們想當我們點擊<a>標簽的時候瀏覽器會打開一個新的tab選項卡來展示我們之前的歡迎頁面,當前的選項卡不進行頁面切換,就要用到.prevent修飾符啦
<a @click.prevent="ddTick" href="http://localhost:8080/#/">跳轉到主頁</a>
ddTick(){
console.log("a標簽你還是太嫩了,我要自己來")
window.open('http://localhost:8080/#/')
}

可以看到 原來<a>標簽的跳轉功能被封印了,執(zhí)行了我們的ddTick()方法,所以.prevent修飾符的功能就是取消標簽自身的默認操作,執(zhí)行自己定義的方法。
注意:.prevent修飾符只能對
cancelable事件屬性的事件起作用
cancelable 事件返回一個布爾值。如果用 preventDefault() 方法可以取消與事件關聯(lián)的默認動作,則為 true,否則為 fasle。
(功能就是這么個功能,但總感覺用法怪怪的。。。如果有大神知道更深層次的用法希望可以留言指點一下~~)
.capture
這是捕獲事件的修飾符,即有此修飾修飾的元素事件觸發(fā)的優(yōu)先級是最高的,例如開始咱們的冒泡例子
<div @click="ccTick">
<div @click.capture ="bbTick">
<button @click="aaTick">點擊一下</button>
</div>
</div>
我們給第二層div增加capture修飾,當執(zhí)行的時候會出現(xiàn)這樣的情況:

可以看到優(yōu)先觸發(fā)了第二層的點擊事件,然后才是對button按鈕的點擊事件,接著是對最外層div的冒泡事件。
.self
<div @click.self="ccTick">
<div @click.self ="bbTick">
<button @click="aaTick">點擊一下</button>
</div>
</div>
當我們將外面的兩層<div>標簽的事件監(jiān)聽加上.self修飾后再次點擊按鈕會發(fā)現(xiàn)

只觸發(fā)了button按鈕自身的單擊事件,可見
.Self只對點擊到自己身上的事件才做出反應
.once
<button @click.once="aaTick">點擊一下</button>

如果加上once修飾符,則事件只能觸發(fā)一次。之后無論點擊多少次都不再觸發(fā)
.passive
passive這個修飾符會執(zhí)行默認方法。你們可能會問,明明默認執(zhí)行為什么會設置這樣一個修飾符。這就要說一下這個修飾符的本意了。
【瀏覽器只有等內(nèi)核線程執(zhí)行到事件監(jiān)聽器對應的JavaScript代碼時,才能知道內(nèi)部是否會調用preventDefault函數(shù)來阻止事件的默認行為,所以瀏覽器本身是沒有辦法對這種場景進行優(yōu)化的。這種場景下,用戶的手勢事件無法快速產(chǎn)生,會導致頁面無法快速執(zhí)行滑動邏輯,從而讓用戶感覺到頁面卡頓?!?br> 通俗點說就是每次事件產(chǎn)生,瀏覽器都會去查詢一下是否有preventDefault阻止該次事件的默認動作。我們加上passive就是為了告訴瀏覽器,不用查詢了,我們沒用preventDefault阻止默認動作。
這里一般用在滾動監(jiān)聽,@scoll,@touchmove 。因為滾動監(jiān)聽過程中,移動每個像素都會產(chǎn)生一次事件,每次都使用內(nèi)核線程查詢prevent會使滑動卡頓。我們通過passive將內(nèi)核線程查詢跳過,可以大大提升滑動的流暢度。
注意:換句話說也就是passive和prevent其實是相反的一個修飾符,prevent是阻止默認事件方法,執(zhí)行自定義函數(shù),而passive是一定執(zhí)行默認事件方法(其他自定義方法也會執(zhí)行)所以兩者是沖突的,不可以同時使用,如果一起使用就會.prevent會失效,同時我們也會收獲瀏覽器的一個警告。