跳到主要内容

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回车
.tabTab
.deleteDelete / Backspace
.escEscape
.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>

系统修饰符

修饰符说明
.ctrlCtrl 键
.altAlt 键
.shiftShift 键
.metaCommand (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 事件处理的内容:

  1. v-on 指令:监听 DOM 事件
  2. 事件处理函数:内联和方法两种形式
  3. 事件修饰符:.stop、.prevent、.self、.once、.passive
  4. 按键修饰符:.enter、.tab 等
  5. 鼠标修饰符:.left、.right、.middle
  6. 系统修饰符:.ctrl、.alt、.shift、.meta
  7. 综合示例:计数器和拖拽功能

练习

  1. 创建一个可以调节字体大小的组件
  2. 实现一个双击点赞功能
  3. 实现一个键盘快捷键功能

准备好进入下一章,学习表单绑定的内容了吗?