首页 > 编程笔记 > JavaScript笔记
Vue事件修饰符详解
Vue 可以对事件添加一些通用的限制,例如添加阻止事件冒泡,Vue 对这种事件的限制提供了特定的写法,称之为修饰符。
Vue 事件修饰符的语法如下:
Vue 事件修饰符处理了许多 DOM 事件的细节,让我们不再需要花费大量的时间去处理这些烦恼的事情,而将更多的精力用于程序的逻辑处理。
在 Vue 中,事件修饰符主要有:
下面分别来看一下每个修饰符的用法。
在下面的示例中,创建一个 div 元素,在其内部也创建一个 div 元素,并分别为它们添加单击事件。根据事件的冒泡机制可以得知,当单击内部的 div 元素之后,会扩散到父元素 div,从而触发父元素的单击事件。
图 1 触发内部元素事件
根据事件的冒泡机制,也会触发外部(outside)元素,效果如下图所示。
图 2 触发外部元素事件
使用 stop 修饰符阻止事件冒泡。修改上面 HTML 对应的代码:
图 3 只触发内部元素事件
在下面的示例中,创建了 3 个 div 元素,把它们分别嵌套,并添加单击事件。为外层的两个 div 元素添加 capture 修饰符,当单击内部的 div 元素时,将从外向内触发含有 capture 修饰符的 div 元素的事件。
self 修饰符会监视事件是否直接作用在元素上,若不是,则冒泡跳过该元素。
例如:
不像其他只能对原生的 DOM 事件起作用的修饰符,once 修饰符还能被用到自定义的组件事件上。
例如:
图 4 once修饰符作用效果
注意,不要把 passive 和 prevent 修饰符一起使用,因为 prevent 将会被忽略,同时浏览器可能会展示一个警告。passive 修饰符会告诉浏览器不想阻止事件的默认行为。
例如:
图 5 prevent修饰符
通俗地说,就是每次事件产生时,浏览器都会去查询一下是否有 preventDefault 阻止该次事件的默认动作,加上 passive 修饰符就是为了告诉浏览器,不用查询了,没有 preventDefault 阻止默认行为。
passive 修饰符一般用在滚动监听、@scoll 和 @touchmove 中。因为滚动监听过程中,移动每个像素都会产生一次事件,每次都使用内核线程查询 prevent 会使滑动卡顿,通过 passive 修饰符将内核线程查询跳过,可以大大提升滑动的流畅度。
注意,使用修饰符时,顺序很重要,相应的代码会以同样的顺序产生。因此,使用 v-on:click.prevent.self 会阻止所有的单击,而 v-on:click.self.prevent 只会阻止对元素自身的单击。
Vue 事件修饰符的语法如下:
v-on:事件.修饰符在事件处理程序中,调用 event.preventDefault()(阻止默认行为)或 event.stopPropagation()(阻止事件冒泡)是非常常见的需求。尽管可以在方法中轻松实现这一点,但更好的方式是使用纯粹的数据逻辑,而不是去处理 DOM 事件细节。
Vue 事件修饰符处理了许多 DOM 事件的细节,让我们不再需要花费大量的时间去处理这些烦恼的事情,而将更多的精力用于程序的逻辑处理。
在 Vue 中,事件修饰符主要有:
- stop:等同于 JavaScript 中的 event.stopPropagation(),阻止事件冒泡。
- capture:与事件冒泡的方向相反,事件捕获由外到内。
- self:只会触发自己范围内的事件。
- once:只会触发一次。
- prevent:等同于 JavaScript 中的 event.preventDefault(),阻止默认事件的发生。
- passive:执行默认行为。
下面分别来看一下每个修饰符的用法。
stop事件修饰符
stop 修饰符用来阻止事件冒泡。在下面的示例中,创建一个 div 元素,在其内部也创建一个 div 元素,并分别为它们添加单击事件。根据事件的冒泡机制可以得知,当单击内部的 div 元素之后,会扩散到父元素 div,从而触发父元素的单击事件。
<head> <meta charset="UTF-8"> <title>冒泡事件</title> <style> .outside{ width: 200px; height: 100px; border: 1px solid red; text-align: center; } .inside{ width: 100px; height: 50px; border:1px solid black; margin:15% 25%; } </style> </head> <body> <div id="app"> <div class="outside" @click="outside"> <div class="inside" @click ="inside">冒泡事件</div> </div> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ methods: { outside: function () { alert("外面div的单击事件") }, inside: function () { alert("内部div的单击事件") } } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>在 Chrome 浏览器中运行程序,单击内部(inside)元素,触发自身事件,效果如下图所示。
图 1 触发内部元素事件
根据事件的冒泡机制,也会触发外部(outside)元素,效果如下图所示。
图 2 触发外部元素事件
使用 stop 修饰符阻止事件冒泡。修改上面 HTML 对应的代码:
<div id="app"> <div class="outside" @click="outside"> <div class="inside" @click.stop="inside">阻止事件冒泡</div> </div> </div>在 Chrome 浏览器中运行程序,单击内部的 div 后,将不再触发父元素单击事件,如下图所示。
图 3 只触发内部元素事件
capture事件修饰符
事件捕获模式与事件冒泡模式是一对相反的事件处理流程,当想要将页面元素的事件流改为事件捕获模式时,只需要在父级元素的事件上使用 capture 修饰符即可。若有多个该修饰符,则由外而内触发。在下面的示例中,创建了 3 个 div 元素,把它们分别嵌套,并添加单击事件。为外层的两个 div 元素添加 capture 修饰符,当单击内部的 div 元素时,将从外向内触发含有 capture 修饰符的 div 元素的事件。
<style> .outside{ width: 300px; height: 180px; color:white; font-size: 30px; background: red; margin-top: 120px; } .center{ width: 200px; height: 120px; background: #17a2b8; } .inside{ width: 100px; height: 60px; background: #a9b4ba; } </style> <div id="app"> <div class="outside" @click.capture="outside"> <div class="center" @click.capture="center"> <div class="inside" @click="inside">内部</div> 中间 </div> 外层 </div> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ methods: { outside:function(){ alert("外面的div") }, center:function(){ alert("中间的div") }, inside: function () { alert("内部的div") } } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>在 Chrome 浏览器中运行程序,单击内部的 div 元素,会先触发添加了 capture 修饰符的外层 div 元素,然后触发中间 div 元素,最后触发单击的内部元素。
self事件修饰符
self 修饰符可以理解为跳过冒泡事件和捕获事件,只有直接作用在该元素上的事件才可以执行。self 修饰符会监视事件是否直接作用在元素上,若不是,则冒泡跳过该元素。
例如:
<style> .outside{ width: 300px; height: 180px; color:white; font-size: 30px; background: red; margin-top: 100px; } .center{ width: 200px; height: 120px; background: #17a2b8; } .inside{ width: 100px; height: 60px; background: #a9b4ba; } </style> <div id="app"> <div class="outside" @click="outside"> <div class="center" @click.self="center"> <div class="inside" @click="inside">内部</div> 中间 </div> 外层 </div> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ methods: { outside: function () { alert("外面的div") }, center: function () { alert("中间的div") }, inside: function () { alert("内部的div") } } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>在 Chrome 浏览器中运行程序,单击内部的 div 后,触发该元素的单击事件。由于中间 div 添加了 self 修饰符,因此直接单击该元素就会跳过,内部 div 执行完毕后,外层的 div 紧接着执行。
once事件修饰符
有时需要只执行一次的操作,比如微信朋友圈点赞,便可以使用 once 修饰符来完成。不像其他只能对原生的 DOM 事件起作用的修饰符,once 修饰符还能被用到自定义的组件事件上。
例如:
<div id="app"> <button @click.once="add">点赞 {{num }}</button> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ //该函数返回数据对象 data(){ return{ num:0 } }, methods:{ add:function(){ this.num +=1 }, } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>在 Chrome 浏览器中运行程序,单击“点赞0”按钮,count 值从 0 变成 1,之后,无论再单击多少次,count 的值仍然是 1,效果如下图所示。
图 4 once修饰符作用效果
prevent事件修饰符
prevent 修饰符用于阻止默认行为,例如 <a> 标签,当单击标签时,默认行为会跳转到对应的链接,如果在 <a> 标签上添加 prevent 修饰符,则不会跳转到对应的链接。注意,不要把 passive 和 prevent 修饰符一起使用,因为 prevent 将会被忽略,同时浏览器可能会展示一个警告。passive 修饰符会告诉浏览器不想阻止事件的默认行为。
例如:
<div id="app"> <div style="margin-top: 100px"> <a @click.prevent="alert()" href="https://cn.vuejs.org" >阻止跳转</a> </div> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ methods:{ alert:function(){ alert("阻止<a>标签的链接") } } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>在 Chrome 浏览器中运行程序,单击“阻止跳转”链接,触发 alert() 事件弹出“阻止 <a> 标签的链接”,效果如下图所示;然后单击“确定”按钮,可以发现页面将不再进行跳转。
图 5 prevent修饰符
passive事件修饰符
明明是默认执行的行为,为什么还要使用 passive 修饰符呢?原因是浏览器只有等内核线程执行到事件监听器对应的 JavaScript 代码时,才能知道内部是否会调用 preventDefault 函数来阻止事件的默认行为,所以浏览器本身是没有办法对这种场景进行优化的。在这种场景下,用户的手势事件无法快速产生,会导致页面无法快速执行滑动逻辑,从而让用户感觉到页面卡顿。通俗地说,就是每次事件产生时,浏览器都会去查询一下是否有 preventDefault 阻止该次事件的默认动作,加上 passive 修饰符就是为了告诉浏览器,不用查询了,没有 preventDefault 阻止默认行为。
passive 修饰符一般用在滚动监听、@scoll 和 @touchmove 中。因为滚动监听过程中,移动每个像素都会产生一次事件,每次都使用内核线程查询 prevent 会使滑动卡顿,通过 passive 修饰符将内核线程查询跳过,可以大大提升滑动的流畅度。
注意,使用修饰符时,顺序很重要,相应的代码会以同样的顺序产生。因此,使用 v-on:click.prevent.self 会阻止所有的单击,而 v-on:click.self.prevent 只会阻止对元素自身的单击。