首页 > 编程笔记 > JavaScript笔记 阅读:58

Vue事件修饰符详解

通义灵码
Vue 可以对事件添加一些通用的限制,例如添加阻止事件冒泡,Vue 对这种事件的限制提供了特定的写法,称之为修饰符。

Vue 事件修饰符的语法如下:
v-on:事件.修饰符
在事件处理程序中,调用 event.preventDefault()(阻止默认行为)或 event.stopPropagation()(阻止事件冒泡)是非常常见的需求。尽管可以在方法中轻松实现这一点,但更好的方式是使用纯粹的数据逻辑,而不是去处理 DOM 事件细节。

Vue 事件修饰符处理了许多 DOM 事件的细节,让我们不再需要花费大量的时间去处理这些烦恼的事情,而将更多的精力用于程序的逻辑处理。

在 Vue 中,事件修饰符主要有:
下面分别来看一下每个修饰符的用法。

stop事件修饰符

stop 修饰符用来阻止事件冒泡。

在下面的示例中,创建一个 div 元素,在其内部也创建一个 div 元素,并分别为它们添加单击事件。根据事件的冒泡机制可以得知,当单击内部的 div 元素之后,会扩散到父元素 div,从而触发父元素的单击事件。
  1. <head>
  2. <meta charset="UTF-8">
  3. <title>冒泡事件</title>
  4. <style>
  5. .outside{
  6. width: 200px;
  7. height: 100px;
  8. border: 1px solid red;
  9. text-align: center;
  10. }
  11. .inside{
  12. width: 100px;
  13. height: 50px;
  14. border:1px solid black;
  15. margin:15% 25%;
  16. }
  17. </style>
  18. </head>
  19. <body>
  20. <div id="app">
  21. <div class="outside" @click="outside">
  22. <div class="inside" @click ="inside">冒泡事件</div>
  23. </div>
  24. </div>
  25. <!--引入Vue文件-->
  26. <script src="https://unpkg.com/vue@next"></script>
  27. <script>
  28. //创建一个应用程序实例
  29. const vm= Vue.createApp({
  30. methods: {
  31. outside: function () {
  32. alert("外面div的单击事件")
  33. },
  34. inside: function () {
  35. alert("内部div的单击事件")
  36. }
  37. }
  38. //在指定的DOM元素上装载应用程序实例的根组件
  39. }).mount('#app');
  40. </script>
在 Chrome 浏览器中运行程序,单击内部(inside)元素,触发自身事件,效果如下图所示。


图 1 触发内部元素事件

根据事件的冒泡机制,也会触发外部(outside)元素,效果如下图所示。


图 2 触发外部元素事件

使用 stop 修饰符阻止事件冒泡。修改上面 HTML 对应的代码:
  1. <div id="app">
  2. <div class="outside" @click="outside">
  3. <div class="inside" @click.stop="inside">阻止事件冒泡</div>
  4. </div>
  5. </div>
在 Chrome 浏览器中运行程序,单击内部的 div 后,将不再触发父元素单击事件,如下图所示。


图 3 只触发内部元素事件

capture事件修饰符

事件捕获模式与事件冒泡模式是一对相反的事件处理流程,当想要将页面元素的事件流改为事件捕获模式时,只需要在父级元素的事件上使用 capture 修饰符即可。若有多个该修饰符,则由外而内触发。

在下面的示例中,创建了 3 个 div 元素,把它们分别嵌套,并添加单击事件。为外层的两个 div 元素添加 capture 修饰符,当单击内部的 div 元素时,将从外向内触发含有 capture 修饰符的 div 元素的事件。
  1. <style>
  2. .outside{
  3. width: 300px;
  4. height: 180px;
  5. color:white;
  6. font-size: 30px;
  7. background: red;
  8. margin-top: 120px;
  9. }
  10. .center{
  11. width: 200px;
  12. height: 120px;
  13. background: #17a2b8;
  14. }
  15. .inside{
  16. width: 100px;
  17. height: 60px;
  18. background: #a9b4ba;
  19. }
  20. </style>
  21. <div id="app">
  22. <div class="outside" @click.capture="outside">
  23. <div class="center" @click.capture="center">
  24. <div class="inside" @click="inside">内部</div>
  25. 中间
  26. </div>
  27. 外层
  28. </div>
  29. </div>
  30. <!--引入Vue文件-->
  31. <script src="https://unpkg.com/vue@next"></script>
  32. <script>
  33. //创建一个应用程序实例
  34. const vm= Vue.createApp({
  35. methods: {
  36. outside:function(){
  37. alert("外面的div")
  38. },
  39. center:function(){
  40. alert("中间的div")
  41. },
  42. inside: function () {
  43. alert("内部的div")
  44. }
  45. }
  46. //在指定的DOM元素上装载应用程序实例的根组件
  47. }).mount('#app');
  48. </script>
在 Chrome 浏览器中运行程序,单击内部的 div 元素,会先触发添加了 capture 修饰符的外层 div 元素,然后触发中间 div 元素,最后触发单击的内部元素。

self事件修饰符

self 修饰符可以理解为跳过冒泡事件和捕获事件,只有直接作用在该元素上的事件才可以执行。

self 修饰符会监视事件是否直接作用在元素上,若不是,则冒泡跳过该元素。

例如:
  1. <style>
  2. .outside{
  3. width: 300px;
  4. height: 180px;
  5. color:white;
  6. font-size: 30px;
  7. background: red;
  8. margin-top: 100px;
  9. }
  10. .center{
  11. width: 200px;
  12. height: 120px;
  13. background: #17a2b8;
  14. }
  15. .inside{
  16. width: 100px;
  17. height: 60px;
  18. background: #a9b4ba;
  19. }
  20. </style>
  21. <div id="app">
  22. <div class="outside" @click="outside">
  23. <div class="center" @click.self="center">
  24. <div class="inside" @click="inside">内部</div>
  25. 中间
  26. </div>
  27. 外层
  28. </div>
  29. </div>
  30. <!--引入Vue文件-->
  31. <script src="https://unpkg.com/vue@next"></script>
  32. <script>
  33. //创建一个应用程序实例
  34. const vm= Vue.createApp({
  35. methods: {
  36. outside: function () {
  37. alert("外面的div")
  38. },
  39. center: function () {
  40. alert("中间的div")
  41. },
  42. inside: function () {
  43. alert("内部的div")
  44. }
  45. }
  46. //在指定的DOM元素上装载应用程序实例的根组件
  47. }).mount('#app');
  48. </script>
在 Chrome 浏览器中运行程序,单击内部的 div 后,触发该元素的单击事件。由于中间 div 添加了 self 修饰符,因此直接单击该元素就会跳过,内部 div 执行完毕后,外层的 div 紧接着执行。

once事件修饰符

有时需要只执行一次的操作,比如微信朋友圈点赞,便可以使用 once 修饰符来完成。

不像其他只能对原生的 DOM 事件起作用的修饰符,once 修饰符还能被用到自定义的组件事件上。

例如:
  1. <div id="app">
  2. <button @click.once="add">点赞 {{num }}</button>
  3. </div>
  4. <!--引入Vue文件-->
  5. <script src="https://unpkg.com/vue@next"></script>
  6. <script>
  7. //创建一个应用程序实例
  8. const vm= Vue.createApp({
  9. //该函数返回数据对象
  10. data(){
  11. return{
  12. num:0
  13. }
  14. },
  15. methods:{
  16. add:function(){
  17. this.num +=1
  18. },
  19. }
  20. //在指定的DOM元素上装载应用程序实例的根组件
  21. }).mount('#app');
  22. </script>
在 Chrome 浏览器中运行程序,单击“点赞0”按钮,count 值从 0 变成 1,之后,无论再单击多少次,count 的值仍然是 1,效果如下图所示。


图 4 once修饰符作用效果

prevent事件修饰符

prevent 修饰符用于阻止默认行为,例如 <a> 标签,当单击标签时,默认行为会跳转到对应的链接,如果在 <a> 标签上添加 prevent 修饰符,则不会跳转到对应的链接。

注意,不要把 passive 和 prevent 修饰符一起使用,因为 prevent 将会被忽略,同时浏览器可能会展示一个警告。passive 修饰符会告诉浏览器不想阻止事件的默认行为。

例如:
  1. <div id="app">
  2. <div style="margin-top: 100px">
  3. <a @click.prevent="alert()" href="https://cn.vuejs.org" >阻止跳转</a>
  4. </div>
  5. </div>
  6. <!--引入Vue文件-->
  7. <script src="https://unpkg.com/vue@next"></script>
  8. <script>
  9. //创建一个应用程序实例
  10. const vm= Vue.createApp({
  11. methods:{
  12. alert:function(){
  13. alert("阻止<a>标签的链接")
  14. }
  15. }
  16. //在指定的DOM元素上装载应用程序实例的根组件
  17. }).mount('#app');
  18. </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 只会阻止对元素自身的单击。

相关文章