在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。修饰符是由点(.)开头的指令后缀来表示的:
修饰符包括
- .stop 阻止单击事件继续传播
- .prevent 取消自身的默认操作,执行自定义方法
- .capture 添加事件监听器时使用事件捕获模式,即元素自身触发的事件先在此处理,然后才交由内部元素进行处理
- .self 只当在 event.target 是当前元素自身时触发处理函数 即事件不是从内部元素触发的
- .once 点击事件将只会触发一次
- .passive 滚动事件的默认行为 (即滚动行为) 将会立即触发 而不会等待 事件方法执行 完成,这其中包含
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("触发了button点击事件");
},
bbTick(){
console.log("触发了二层div点击事件");
},
ccTick(){
console.log("触发了最外层div点击事件");
},
}
}
</script>
我们的模板里的button按钮外面包裹着两层div,而且三者都有监听点击事件,那么我们点击按钮的时候会怎样呢?:
可以看出来点击按钮后三者都触发了点击事件,而且触发顺序是由里到外冒泡触发,很多时候我们肯定是不需要在一个按钮上触发其他的点击事件的,(当然流氓网页除外)原生的JS给我们提供了一些方法来解决如:
event.stopPropagation()
; 即我们可以这样:用特殊变量
$event
把它传入方法
<button @click="aaTick($event)">点击一下</button>
aaTick(event){
console.log("触发了button点击事件");
event.stopPropagation();
}
通过event对象的stopPropagation()
方法组织冒泡产生
当然这样的解决方案是很不优雅的,vue给我们封装了修饰符来应对这种情况:
<button @click.stop="aaTick">点击一下</button>
效果一样
.prevent
<a href="http://localhost:8080/#/">跳转到主页</a>
我们增加一个<a>标签,让它点击触发的时候跳转到欢迎主页面
但是我们不想让他跳转,我们想当我们点击<a>标签的时候浏览器会打开一个新的tab选项卡来展示我们之前的欢迎页面,当前的选项卡不进行页面切换,就要用到.prevent
修饰符啦
<a @click.prevent="ddTick" href="http://localhost:8080/#/">跳转到主页</a>
ddTick(){
console.log("a标签你还是太嫩了,我要自己来")
window.open('http://localhost:8080/#/')
}
可以看到 原来<a>标签的跳转功能被封印了,执行了我们的ddTick()方法,所以.prevent修饰符的功能就是取消标签自身的默认操作,执行自己定义的方法。
注意:.prevent修饰符只能对
cancelable事件属性
的事件起作用
cancelable 事件返回一个布尔值。如果用 preventDefault() 方法可以取消与事件关联的默认动作,则为 true,否则为 fasle。
(功能就是这么个功能,但总感觉用法怪怪的。。。如果有大神知道更深层次的用法希望可以留言指点一下~~)
.capture
这是捕获事件的修饰符,即有此修饰修饰的元素事件触发的优先级是最高的,例如开始咱们的冒泡例子
<div @click="ccTick">
<div @click.capture ="bbTick">
<button @click="aaTick">点击一下</button>
</div>
</div>
我们给第二层div增加capture修饰,当执行的时候会出现这样的情况:
可以看到优先触发了第二层的点击事件,然后才是对button按钮的点击事件,接着是对最外层div的冒泡事件。
.self
<div @click.self="ccTick">
<div @click.self ="bbTick">
<button @click="aaTick">点击一下</button>
</div>
</div>
当我们将外面的两层<div>标签的事件监听加上.self修饰后再次点击按钮会发现
只触发了button按钮自身的单击事件,可见
.Self
只对点击到自己身上的事件才做出反应
.once
<button @click.once="aaTick">点击一下</button>
如果加上once修饰符,则事件只能触发一次。之后无论点击多少次都不再触发
.passive
passive这个修饰符会执行默认方法。你们可能会问,明明默认执行为什么会设置这样一个修饰符。这就要说一下这个修饰符的本意了。
【浏览器只有等内核线程执行到事件监听器对应的JavaScript代码时,才能知道内部是否会调用preventDefault函数来阻止事件的默认行为,所以浏览器本身是没有办法对这种场景进行优化的。这种场景下,用户的手势事件无法快速产生,会导致页面无法快速执行滑动逻辑,从而让用户感觉到页面卡顿。】
通俗点说就是每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。我们加上passive就是为了告诉浏览器,不用查询了,我们没用preventDefault阻止默认动作。
这里一般用在滚动监听,@scoll,@touchmove 。因为滚动监听过程中,移动每个像素都会产生一次事件,每次都使用内核线程查询prevent会使滑动卡顿。我们通过passive将内核线程查询跳过,可以大大提升滑动的流畅度。
注意:换句话说也就是passive和prevent其实是相反的一个修饰符,prevent是阻止默认事件方法,执行自定义函数,而passive是一定执行默认事件方法(其他自定义方法也会执行)所以两者是冲突的,不可以同时使用,如果一起使用就会.prevent会失效,同时我们也会收获浏览器的一个警告。