在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.stop 阻止单击事件继续传播
.prevent 拦截默认事件
.capture 添加事件监听器时使用事件捕获模式
.self 自身处理函数修饰符
.once 在 2.1.4 新增,单次调用修饰符
.passive 在 2.3.0 新增,不拦截默认事件, 与 JavaScript 中的 addEventListener 的 passive 选项一致功能。
使用示例如下:
<!-- 阻止单击事件继续传播 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件不再重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修饰符可以串联 --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只有修饰符 --> <form v-on:submit.prevent></form> <!-- 添加事件监听器时使用事件捕获模式 --> <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 --> <div v-on:click.capture="doThis">...</div> <!-- 只当在 event.target 是当前元素自身时触发处理函数 --> <!-- 即事件不是从内部元素触发的 --> <div v-on:click.self="doThat">...</div>
注意:使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
该修饰符用于阻止事件冒泡,与 event.stopPropagation() 效果相同。
阻止事件冒泡,当一个元素执行某个事件的时候,这个事件会一直向上传播,如果它的父元素也有相同的事件,也会被触发执行。如果不想让事件向上传播,就需要阻止事件冒泡。
例如:
<div id="app"> <div @click="myClick1"> <p @click.stop="myClick2">阻止事件冒泡</p> </div> </div> <script type="text/javascript"> var app = new Vue({ el: "#app", data: {}, methods: { myClick1: function() { alert("我是DIV标签"); }, myClick2: function() { alert("我是P标签"); } } }); </script>
注意:如果没有 stop 修饰符,点击后两个事件(myClick1、myClick2)都会触发。而现在只有 myClick2 触发执行。
该修饰符用于阻止默认事件,与 event.preventDefault() 效果相同。
阻止默认事件,某些标签带有默认的事件,例如 a 标签默认跳转页面、submit 属性默认提交并刷新页面。如果不想触发这些默认的事件,就需要阻止默认事件了。
例如:
<div id="app"> <a href="http://www.hxstrive.com" @click.prevent="info">人人编程网</a> </div> <script type="text/javascript"> var app = new Vue({ el: "#app", data: {}, methods: { info: function() { alert("显示信息"); } } }); </script>
注意:如果没有 prevent 修饰符,点击链接后会跳转到人人编程网,而现在点击后不会跳转页面。
该修饰符用于让事件以捕获模式触发。例如:
<div id="app"> <div class="box" @click.capture="myClick1" style="background:red;"> 我是div标签 <p @click="myClick2" style="background:blue;">我是p标签</p> 我是div标签 </div> </div> <script type="text/javascript"> var app = new Vue({ el: "#app", data: {}, methods: { myClick1: function() { alert("外"); }, myClick2: function() { alert("内"); } } }); </script>
注意:如果没有 capture 修饰符,事件默认冒泡阶段触发,会先执行内,后执行外。而现在 myClick1 事件在捕获阶段触发,会先执行外,后执行内。
该修饰符用于指定事件不会被事件冒泡或事件捕获触发,只有操作当前元素才会触发。例如:
<div id="app"> <div class="box" @click.self="info"> 内容 <button @click="info">按钮</button> </div> </div> <script type="text/javascript"> var app = new Vue({ el: "#app", data: {}, methods: { info: function(e){ alert(e.target); } } }); </script>
注意:如果没有 self 修饰符,点击按钮时,事件会向上传播,导致 div 上的事件也会被触发。而现在点击按钮不会触发 div 上的事件,只有点击 “内容” 才能执行 div 上的事件。
该修饰符不像其它修饰符只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的组件事件上。例如:
<!-- 点击事件将只会触发一次 --> <a v-on:click.once="doThis"></a>
Vue.js 还为 addEventListener 中的 passive 选项提供了 .passive 修饰符,这个 .passive 修饰符尤其能够提升移动端的性能。常用于 scroll 事件,可以使内容立即滚动,不需要等待事件执行完毕。例如:
<div id="app"> <ul class="list" @scroll.passive="demo"> <li v-for="row of rows" :key="row">{{ row }}</li> </ul> </div> <script type="text/javascript"> var app = new Vue({ el: "#app", data: {}, computed: { rows: function(){ var _t = []; for(var i = 0; i < 100; i++) { _t.push(i); } return _t; } }, methods: { demo: function(){ for(var i = 0; i < 10000; i++){ console.log(i); } console.log("执行完毕!"); } } }); </script>
注意:推荐给 scroll 事件添加 passive 修饰符,它能够提升移动端的性能。避免等待事件执行完毕后才能触发内容滚动。不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。