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. 最佳实践

  1. 命名规范:使用 kebab-case 命名自定义事件

  2. 参数传递:传递有意义的参数,避免过多依赖事件对象

  3. 解耦:组件事件应尽量保持组件间的解耦

  4. 清理:在组件卸载时清理事件监听器

  5. 类型安全:使用 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 中提供了更灵活的方式来管理和组织事件逻辑。

 

posted @ 2026-02-10 15:01  麻辣~香锅  阅读(2)  评论(0)    收藏  举报