Vue 事件处理
Vue 使用 v-on 指令监听 DOM 事件,并在触发时执行相应的处理函数。本章将详细介绍 Vue 的事件处理机制。
基本用法
监听事件
使用 v-on 指令监听 DOM 事件:
<button v-on:click="handleClick">点击</button>
<script setup>
function handleClick() {
console.log('按钮被点击')
}
</script>
简写形式
v-on: 可以简写为 @:
<!-- 完整写法 -->
<button v-on:click="handleClick">点击</button>
<!-- 简写 -->
<button @click="handleClick">点击</button>
事件处理函数
内联处理函数
可以直接在模板中写简单的逻辑:
<button @click="count++">增加</button>
<p>计数: {{ count }}</p>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
方法处理函数
将逻辑封装到方法中:
<button @click="increment">增加</button>
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
传递参数
可以向事件处理函数传递参数:
<button @click="greet('Hello')">问候</button>
<button @click="say('你好', $event)">打招呼</button>
<script setup>
function greet(message) {
alert(message)
}
function say(text, event) {
console.log(text, event.target)
}
</script>
提示
$event 是 Vue 提供的特殊变量,表示原生的事件对象。
事件修饰符
Vue 提供了事件修饰符来简化常见的事件处理需求:
.stop - 阻止事件传播
<!-- 阻止冒泡 -->
<div @click="outer">
<button @click.stop="handleClick">点击</button>
</div>
<script setup>
function outer() {
console.log('outer clicked')
}
function handleClick() {
console.log('button clicked')
}
</script>
输出结果(没有 .stop 时):
button clicked
outer clicked
使用 .stop 后:
button clicked
.prevent - 阻止默认行为
<!-- 阻止表单提交默认行为 -->
<form @submit.prevent="handleSubmit">
<input type="submit" value="提交" />
</form>
<!-- 阻止链接跳转 -->
<a href="https://vuejs.org" @click.prevent>Vue 官网</a>
<script setup>
function handleSubmit() {
console.log('表单提交')
}
</script>
.capture - 使用事件捕获模式
<div @click.capture="handleOuter">
<button @click="handleInner">点击</button>
</div>
使用捕获模式后,事件从外层向内层传播。
.self - 只有事件目标是自己时才触发
<!-- 只有点击 div 本身时才触发,点击子元素不触发 -->
<div @click.self="handleClick">
<button>按钮</button>
</div>
.once - 事件只触发一次
<!-- 点击只会触发一次 -->
<button @click.once="handleClick">点击</button>
.passive - 监听器使用 passive 模式
<!-- 提升滚动性能 -->
<div @scroll.passive="handleScroll">内容</div>
提示
.passive 修饰符通常用于提升移动端滚动性能,告诉浏览器不会阻止默认行为。
键盘修饰符
监听键盘事件时,可以使用按键修饰符:
常用按键别名
| 别名 | 对应键 |
|---|---|
| .enter | 回车 |
| .tab | Tab |
| .delete | Delete / Backspace |
| .esc | Escape |
| .space | 空格 |
| .up | 上箭头 |
| .down | 下箭头 |
| .left | 左箭头 |
| .right | 右箭头 |
使用示例
<!-- 按回车时提交 -->
<input @keyup.enter="handleSubmit" />
<!-- 按 Ctrl+Enter 时提交 -->
<textarea @keydown.ctrl.enter="handleSubmit"></textarea>
<!-- 按 Escape 时关闭 -->
<dialog @keyup.esc="close" />
自定义按键修饰符
可以通过 config.globalProperties 定义全局按键别名:
// main.js
app.config.globalProperties.keyCodes = {
f1: 112,
'media-play-pause': 0x11B000
}
<input @keyup.f1="help" />
鼠标修饰符
| 修饰符 | 说明 |
|---|---|
| .left | 鼠标左键 |
| .right | 鼠标右键 |
| .middle | 鼠标中键 |
<!-- 只有右键点击触发 -->
<div @contextmenu.prevent="handleRightClick"></div>
系统修饰符
| 修饰符 | 说明 |
|---|---|
| .ctrl | Ctrl 键 |
| .alt | Alt 键 |
| .shift | Shift 键 |
| .meta | Command (Mac) 或 Windows 键 (Win) |
<!-- Ctrl + 点击 -->
<button @click.ctrl="handleClick">点击</button>
<!-- Alt + 点击 -->
<button @click.alt="handleClick">点击</button>
<!-- 组合键 -->
<button @click.ctrl.shift="handleClick">点击</button>
综合示例:计数器
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment(step = 1) {
count.value += step
}
function decrement(step = 1) {
count.value -= step
}
function reset() {
count.value = 0
}
</script>
<template>
<div class="counter">
<h2>计数器</h2>
<p class="count">{{ count }}</p>
<div class="buttons">
<button @click="decrement(1)">-1</button>
<button @click="decrement(5)">-5</button>
<button @click="reset">重置</button>
<button @click="increment(5)">+5</button>
<button @click="increment(1)">+1</button>
</div>
</div>
</template>
<style scoped>
.counter {
text-align: center;
max-width: 300px;
margin: 0 auto;
}
.count {
font-size: 48px;
font-weight: bold;
color: #42b883;
}
.buttons {
display: flex;
gap: 10px;
justify-content: center;
}
button {
padding: 8px 16px;
font-size: 16px;
cursor: pointer;
}
</style>
综合示例:拖拽元素
<script setup>
import { ref } from 'vue'
const isDragging = ref(false)
const position = ref({ x: 0, y: 0 })
const offset = ref({ x: 0, y: 0 })
function startDrag(event) {
isDragging.value = true
offset.value = {
x: event.clientX - position.value.x,
y: event.clientY - position.value.y
}
}
function onDrag(event) {
if (!isDragging.value) return
position.value = {
x: event.clientX - offset.value.x,
y: event.clientY - offset.value.y
}
}
function stopDrag() {
isDragging.value = false
}
</script>
<template>
<div
class="draggable"
:class="{ dragging: isDragging }"
:style="{ left: position.x + 'px', top: position.y + 'px' }"
@mousedown="startDrag"
@mousemove="onDrag"
@mouseup="stopDrag"
@mouseleave="stopDrag"
>
拖拽我
</div>
</template>
<style scoped>
.draggable {
position: fixed;
width: 100px;
height: 100px;
background: #42b883;
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: move;
user-select: none;
}
.draggable.dragging {
opacity: 0.8;
cursor: grabbing;
}
</style>
小结
本章我们详细学习了 Vue 事件处理的内容:
- v-on 指令:监听 DOM 事件
- 事件处理函数:内联和方法两种形式
- 事件修饰符:.stop、.prevent、.self、.once、.passive
- 按键修饰符:.enter、.tab 等
- 鼠标修饰符:.left、.right、.middle
- 系统修饰符:.ctrl、.alt、.shift、.meta
- 综合示例:计数器和拖拽功能
练习
- 创建一个可以调节字体大小的组件
- 实现一个双击点赞功能
- 实现一个键盘快捷键功能
准备好进入下一章,学习表单绑定的内容了吗?