07Vue3 事件处理
1. 基本概念
在 Vue 3 中,事件处理是组件交互的核心部分。Vue 使用 v-on 指令(简写为 @)来监听 DOM 事件,并在触发时执行相应的 JavaScript 代码。
2. 基本用法
2.1 内联事件处理器
<template>
<button @click="count++">点击次数: {{ count }}</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
2.2 方法事件处理器
<template> <button @click="handleClick">点击我</button> </template> <script setup> const handleClick = () => { console.log('按钮被点击了!') alert('Hello Vue 3!') } </script>
3. 事件修饰符
Vue 提供了一些事件修饰符来处理常见的 DOM 事件细节。
3.1 常用修饰符
<template>
<!-- 阻止默认行为 -->
<form @submit.prevent="onSubmit">
<button type="submit">提交</button>
</form>
<!-- 阻止事件冒泡 -->
<div @click="outerClick">
<div @click.stop="innerClick">内部区域</div>
</div>
<!-- 事件只触发一次 -->
<button @click.once="doOnce">只能点击一次</button>
<!-- 按键修饰符 -->
<input @keyup.enter="submitForm" placeholder="按回车提交" />
<input @keyup.ctrl.enter="submitForm" placeholder="按Ctrl+回车提交" />
<!-- 鼠标按键修饰符 -->
<div @click.right="rightClick">右键点击我</div>
<div @click.middle="middleClick">中键点击我</div>
</template>
3.2 按键修饰符
<template>
<!-- 特定按键 -->
<input @keyup.enter="submit" />
<input @keyup.tab="nextField" />
<input @keyup.delete="deleteItem" />
<!-- 系统按键修饰符 -->
<input @keyup.ctrl.enter="ctrlEnter" />
<input @keyup.shift.space="shiftSpace" />
<!-- 精确修饰符 -->
<button @click.ctrl.exact="ctrlClick">只有 Ctrl 被按下时才触发</button>
</template>
4. 事件参数传递
4.1 传递原生事件
<template> <!-- 自动传递事件对象 --> <button @click="handleClick">点击</button> <!-- 手动传递事件对象 --> <button @click="handleClick($event)">点击</button> </template> <script setup> const handleClick = (event) => { console.log('事件对象:', event) console.log('目标元素:', event.target) } </script>
4.2 传递自定义参数
<template>
<button @click="handleClick('参数1', '参数2', $event)">点击</button>
</template>
<script setup>
const handleClick = (param1, param2, event) => {
console.log('参数1:', param1)
console.log('参数2:', param2)
console.log('事件对象:', event)
}
</script>
5. 组件事件
5.1 子组件触发事件
<!-- ChildComponent.vue --> <template> <button @click="emitClick">点击触发事件</button> </template> <script setup> import { defineEmits } from 'vue' // 定义可触发的事件 const emit = defineEmits(['click', 'custom-event']) const emitClick = () => { // 触发 click 事件 emit('click') // 触发带参数的事件 emit('custom-event', '参数1', '参数2') } </script>
5.2 父组件监听事件
<!-- ParentComponent.vue --> <template> <ChildComponent @click="handleChildClick" @custom-event="handleCustomEvent" /> </template> <script setup> import ChildComponent from './ChildComponent.vue' const handleChildClick = () => { console.log('子组件点击事件被触发') } const handleCustomEvent = (param1, param2) => { console.log('自定义事件:', param1, param2) } </script>
6. 高级用法
6.1 多个事件处理器
<template> <button @click="firstHandler(); secondHandler()">点击触发多个方法</button> </template> <script setup> const firstHandler = () => { console.log('第一个处理器') } const secondHandler = () => { console.log('第二个处理器') } </script>
6.2 动态事件名
<template> <button @[eventName]="handleEvent">动态事件</button> </template> <script setup> import { ref } from 'vue' const eventName = ref('click') const handleEvent = () => { console.log('动态事件被触发') } // 可以动态改变监听的事件 setTimeout(() => { eventName.value = 'mouseenter' }, 2000) </script>
6.3 事件总线(Event Bus)替代方案
// eventBus.js import mitt from 'mitt' export const emitter = mitt() // ComponentA.vue import { emitter } from './eventBus' emitter.emit('event-name', data) // ComponentB.vue import { emitter } from './eventBus' import { onMounted, onUnmounted } from 'vue' onMounted(() => { emitter.on('event-name', handleEvent) }) onUnmounted(() => { emitter.off('event-name', handleEvent) })
7. 最佳实践
-
命名规范:使用 kebab-case 命名自定义事件
-
参数传递:传递有意义的参数,避免过多依赖事件对象
-
解耦:组件事件应尽量保持组件间的解耦
-
清理:在组件卸载时清理事件监听器
-
类型安全:使用 TypeScript 定义事件类型
<!-- 使用 TypeScript 的类型定义 --> <script setup lang="ts"> interface Emits { (e: 'update:modelValue', value: string): void (e: 'submit', payload: { id: number, data: any }): void } const emit = defineEmits<Emits>() </script>
8. Composition API 中的事件处理
<template> <div @mousemove="handleMouseMove" @mouseleave="handleMouseLeave" > 鼠标位置: {{ x }}, {{ y }} </div> </template> <script setup> import { ref, onMounted, onUnmounted } from 'vue' const x = ref(0) const y = ref(0) const handleMouseMove = (event) => { x.value = event.clientX y.value = event.clientY } const handleMouseLeave = () => { x.value = 0 y.value = 0 } // 手动添加事件监听器 onMounted(() => { window.addEventListener('resize', handleResize) }) onUnmounted(() => { window.removeEventListener('resize', handleResize) }) const handleResize = () => { console.log('窗口大小改变了') } </script>
Vue 3 的事件处理系统保持了 Vue 2 的简洁性,同时在 Composition API 中提供了更灵活的方式来管理和组织事件逻辑。

浙公网安备 33010602011771号