在前面的学习里,我们已经多次使用了事件绑定,比如@click。但在实际开发中,我们经常需要处理更复杂的事件场景,比如阻止事件冒泡、阻止默认行为、监听特定按键等。Vue提供了丰富的事件修饰符和按键修饰符来简化这些操作。
在这一堂课中,我们将深入学习Vue的事件处理机制,了解各种修饰符的用法,以及如何编写高效的事件处理代码。这些知识将帮助你构建更加交互性强的应用。

让我们先详细地回顾一下事件处理的基础知识。在Vue中,我们通过v-on指令来监听DOM事件,例如v-on:click,它的简写形式为@click。无论是监听点击、输入还是其它常见的DOM事件,你都可以使用这种语法将事件与你组件的方法进行绑定。
当事件被触发时,所绑定的方法就会被调用。例如,如果你在一个按钮上写@click="handleClick",当按钮被点击时,handleClick方法就会执行:
|<div id="app"> <button @click="handleClick">点击我</button> </div> <script> const { createApp, ref } = Vue; const app = createApp({ setup() { const handleClick = () => { alert('按钮被点击了!'); }; return { handleClick }; } }); app.mount('#app'); </script>
在实际开发中,我们经常需要阻止事件的默认行为或阻止事件冒泡。在原生JavaScript中,我们需要调用event.preventDefault()或event.stopPropagation()。Vue提供了事件修饰符来简化这些操作。
.stop修饰符用于阻止事件冒泡。事件冒泡是指事件从触发元素向上传播到父元素的过程。
让我们看一个例子:
|<div id="app"> <div @click="handleOuterClick" style="padding: 20px; background: #f0f0f0;"> 外层div <button @click="handleInnerClick">内层按钮</button> </div> </div> <script> const { createApp } = Vue;
如果你运行这段代码并点击按钮,你会看到两个提示框:先显示"按钮被点击了",然后显示"外层div被点击了"。这是因为点击事件从按钮冒泡到了外层的div。
如果我们只想触发按钮的点击事件,不想触发外层div的点击事件,可以使用.stop修饰符:
|<div id="app"> <div @click="handleOuterClick" style="padding: 20px; background: #f0f0f0;"> 外层div <button @click.stop="handleInnerClick">内层按钮</button> </div> </div>
现在,当你点击按钮时,只会显示"按钮被点击了",不会触发外层div的点击事件。
.prevent修饰符用于阻止事件的默认行为。最常见的场景是阻止表单提交或链接跳转。
让我们看一个表单的例子:
|<div id="app"> <form @submit="handleSubmit"> <input type="text" v-model="username" placeholder="用户名"> <button type="submit">提交</button> </form> </div> <script>
在这个例子中,我们在handleSubmit方法中手动调用了event.preventDefault()来阻止表单的默认提交行为。
使用.prevent修饰符可以简化这个操作:
|<div id="app"> <form @submit.prevent="handleSubmit"> <input type="text" v-model="username" placeholder="用户名"> <button type="submit">提交</button> </form> </div> <script>
使用.prevent修饰符后,我们不需要在方法中手动调用event.preventDefault(),Vue会自动处理。
.capture修饰符用于使用事件捕获模式。在事件捕获模式下,事件从外层元素向内层元素传播,与事件冒泡相反。
|<div id="app"> <div @click.capture="handleOuterClick" style="padding: 20px; background: #f0f0f0;"> 外层div(捕获模式) <button @click="handleInnerClick">内层按钮</button> </div> </div> <script> const { createApp } = Vue;
在这个例子中,当你点击按钮时,会先显示"外层div被点击了(捕获阶段)",然后显示"按钮被点击了"。这是因为使用了.capture修饰符,事件在捕获阶段就被外层div处理了。
.self 修饰符的作用是确保事件处理函数只会在事件直接发生在绑定事件的元素本身时才被触发,而不是由其子元素冒泡上来的事件。例如,如果你给一个 div 添加了 @click.self 事件监听器,那么只有鼠标点击这个 div 空白区域时才会触发事件;
如果点击的是 div 内的某个按钮或其他子元素,则事件不会触发。这样可以防止因为事件冒泡导致父元素的事件处理函数被意外执行。
|<div id="app"> <div @click.self="handleDivClick" style="padding: 20px; background: #f0f0f0;"> 点击这个div(不是子元素)才会触发 <button>按钮</button> </div> </div> <script> const { createApp } = Vue; const app =
在这个例子中,只有当你直接点击div(而不是按钮)时,才会触发handleDivClick。如果你点击按钮,事件不会触发,因为事件目标不是div本身。
.once 修饰符的作用是让事件处理函数在第一次触发后自动解绑,也就是说,当你使用 .once 修饰符时,事件处理函数只会执行一次,无论你后面再点击多少次,这个处理函数都不会再被调用。
这对于需要在某些场景(比如用户只允许操作一次、提交一次表单、防止重复操作等)自动禁止后续事件响应的需求非常有用。
当你在 Vue 的事件监听中写 @click.once="handleClick",第一次点击会触发 handleClick 方法,触发完成后该监听器会被移除,后续点击不会再触发该方法。
|<div id="app"> <button @click.once="handleClick">只能点击一次</button> </div> <script> const { createApp } = Vue; const app = createApp({ setup() { const handleClick = () => {
在这个例子中,无论你点击按钮多少次,handleClick只会被调用一次。
.passive 修饰符的作用是告诉浏览器,事件处理函数内部 不会 调用 event.preventDefault() 方法。这样浏览器可以提前做出优化,比如在监听滚动(scroll)、触摸滑动(touchmove)等高频事件时,不用等待事件处理函数执行完毕再响应页面滑动,从而提升了页面的滚动流畅度和性能。
一般来说,如果你不需要阻止事件的默认行为(比如页面滚动或者元素滑动),就可以使用 .passive 修饰符。例如:
scroll 事件时,使用 .passive 告诉浏览器你不会阻止滚动行为,有助于提升滚动的性能和流畅性。touchstart、touchmove 事件时,如果你只是做一些数据处理,不需要阻止默认的滚动和滑动,也应使用 .passive。需要注意的是,.passive 和 .prevent 两个修饰符不能同时使用,因为前者要求不调用 preventDefault(),而后者则正是调用了 preventDefault(),两者目标相反。
|<div id="app"> <div @scroll.passive="handleScroll" style="height: 200px; overflow-y: scroll;"> <div style="height: 1000px;">滚动内容</div> </div> </div> <script> const { createApp } = Vue; const
事件修饰符可以链式调用:
|<div id="app"> <a @click.stop.prevent="handleClick" href="https://vuejs.org"> 点击我(不会跳转,也不会冒泡) </a> </div> <script> const { createApp } = Vue; const app = createApp({ setup() {
在这个例子中,.stop.prevent会同时阻止事件冒泡和默认行为。修饰符的顺序很重要,它们会按照从左到右的顺序执行。
Vue 提供了按键修饰符,它可以让我们只在特定的键盘按键被触发时才执行事件处理函数。比如,你可以仅在用户按下 Enter、Esc、Delete、方向键等时处理逻辑,而不用在回调里手动判断 event.key 或 event.keyCode。
这对于优化表单输入、实现键盘快捷键或过滤无关输入等使用场景非常实用。例如,在一个输入框监听 enter 键,用户按下回车时自动提交表单。
Vue为常用的按键提供了修饰符:
|<div id="app"> <input @keyup.enter="handleEnter" @keyup.esc="handleEsc" @keyup.delete="handleDelete" placeholder="按Enter、Esc或Delete键" > </div> <script> const { createApp } = Vue; const app = createApp
Vue提供的按键修饰符包括:.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right等
除了使用按键修饰符来监听特定按键,我们还可以通过在指令后面添加按键的数值编码(即“按键码”)来触发事件。例如,@keyup.13 将只在用户按下键盘的 Enter(回车)键时触发,因为 Enter 键的按键码是 13。这样做相当于手动指定了触发条件,适用于一些特殊或没有内置修饰符的按键。
不过,随着浏览器标准的演进,按键码逐渐被弃用,因此更推荐使用语义化的按键修饰符。
|<div id="app"> <input @keyup.13="handleEnter" placeholder="按Enter键(按键码13)"> </div> <script> const { createApp } = Vue; const app = createApp({ setup() { const handleEnter = () =>
Vue还提供了系统修饰键的修饰符:.ctrl、.alt、.shift、.meta(在Mac上是Command键,在Windows上是Windows键)。
|<div id="app"> <input @keyup.ctrl.enter="handleCtrlEnter" placeholder="按Ctrl+Enter" > </div> <script> const { createApp } = Vue; const app = createApp({ setup() { const handleCtrlEnter =
系统修饰键可以组合使用,比如.ctrl.shift.enter表示同时按下Ctrl、Shift和Enter键。
.exact修饰符用于精确控制修饰键的组合。当你给一个事件添加 .exact 修饰符时,只有在仅按下指定的修饰键(如 Ctrl、Shift、Alt、Meta),且没有其他额外修饰键被同时按下时,相关的事件处理函数才会触发。
举例来说,@click.ctrl.exact 只会在用户按下 Ctrl 并点击时触发,如果同时还按着 Shift 或其他修饰键,则不会触发。
|<div id="app"> <button @click.ctrl="handleCtrlClick">Ctrl+点击</button> <button @click.ctrl.exact="handleExactCtrlClick">仅Ctrl+点击(不能有其他修饰键)</button> </div> <script> const { createApp } = Vue; const app = createApp({
Vue 还为鼠标事件提供了专门的鼠标按钮修饰符,分别是:.left(鼠标左键)、.right(鼠标右键)、.middle(鼠标中键)。你可以在事件绑定时通过这些修饰符,限定事件处理器只在对应的鼠标按钮被点击时触发。例如:
@click.left 只会在点击鼠标左键时触发;@click.right 只会在点击鼠标右键时触发(注意需要配合 @contextmenu.prevent 阻止默认菜单);@click.middle 只会在按下鼠标中键(滚轮)点击时触发。这种修饰符的用法可以让你针对不同的鼠标按键,分别设置不同的操作逻辑,提升用户交互的灵活性。
|<div id="app"> <button @click.left="handleLeftClick">左键点击</button> <button @click.right="handleRightClick">右键点击</button> <button @click.middle="handleMiddleClick">中键点击</button> </div> <script> const { createApp } =
除了调用已定义的方法,我们还可以在模板中直接编写内联的 JavaScript 表达式,将其作为事件处理逻辑。这种写法无需提前在 setup 或 methods 中声明一个方法,可以直接将简单的表达式或一段 JS 代码写进事件绑定里。
常见用法比如直接修改某个响应式数据、调用已有的方法,或者基于事件对象做出简单判断与操作。适合用于操作逻辑很简单、仅涉及几行代码的场景,可以让模板更简洁。例如:
|<div id="app"> <button @click="count++">增加计数</button> <p>计数:{{ count }}</p> </div> <script> const { createApp, ref } = Vue; const app = createApp({ setup() {
在这个例子中,我们直接在@click中写count++,当按钮被点击时,count的值会直接增加。
内联处理也可以访问事件对象:
|<div id="app"> <button @click="alert('按钮被点击了!')">点击我</button> </div> <script> const { createApp } = Vue; const app = createApp({}); app.mount('#app'); </script
在事件处理函数内部,我们可以通过参数接收原生的 DOM 事件对象,这个对象包含了触发事件时的所有相关信息。例如,在绑定的事件方法中声明一个参数 event,Vue 会自动将原生事件对象传递进来。
通过这个事件对象,我们可以访问和操作事件的属性,如目标元素(event.target)、当前绑定元素(event.currentTarget)、鼠标坐标、键盘状态等,从而实现更细致的事件响应逻辑。
|<div id="app"> <button @click="handleClick">点击我</button> </div> <script> const { createApp } = Vue; const app = createApp({ setup() { const handleClick = (event) =>
下面我们通过一个更完整和详细的综合示例,来巩固前面学到的事件绑定、事件修饰符、按键修饰符等知识点。本例将实现一个带有用户名、邮箱和密码输入框的注册表单,演示如何:
@submit.prevent 阻止表单默认提交和页面刷新行为。v-model 实现输入框的数据双向绑定。@keyup.enter 监听回车键,实现输入后自动聚焦到下一个表单项,提升用户体验。ref 获取 DOM 元素,引导输入框焦点切换。@click.once 让“重置”按钮只能点击一次,防止重复操作。v-if 显示“提交成功”的提示。|<div id="app"> <h2>用户注册</h2> <form @submit.prevent="handleSubmit"> <div> <label>用户名:</label> <input v-model="form.username" @keyup.enter="focusNext('email')" placeholder="输入用户名,按Enter跳转到邮箱" >
在这个例子中,我们使用了多种事件处理技巧。表单使用.prevent修饰符阻止默认提交行为,输入框使用.enter修饰符监听Enter键,重置按钮使用.once修饰符确保只能点击一次。
|<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>事件处理示例</title> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
在这一部分中,我们了解了Vue的事件处理机制。我们学习了各种事件修饰符(.stop、.prevent、.capture、.self、.once、.passive)的用法,同时也学习了按键修饰符和系统修饰键,以及如何编写高效的事件处理代码。
事件处理是构建交互式应用的基础。掌握这些知识后,你就能处理各种复杂的用户交互场景。
在下一堂课,我们将学习表单的处理,了解v-model指令的用法,以及如何实现双向数据绑定。这将帮助我们构建更加动态和交互性强的表单。