事件处理快速入门
Q: Vue3 中如何绑定事件?v-on 有哪些使用技巧?
A: 在 Vue 中绑定事件使用内置指令 v-on,指定事件类型和处理函数即可。使用方式非常直观,和原生 JS 的事件绑定思路一致,但多了很多贴心的增强功能。
<template>
<div>{{ count }}</div>
<button v-on:click="add">+1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function add() {
count.value++;
}
</script>
事件处理的各种细节
1. 内联事件处理器
如果事件逻辑非常简单,可以将处理逻辑直接写在模板中:
<template>
<div>{{ count }}</div>
<button v-on:click="count++">+1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
这种方式仅适合极简单的逻辑,稍复杂的情况还是推荐使用独立的方法。
2. 简写形式
绑定事件是一个高频操作,Vue 提供了 @ 符号作为 v-on: 的简写:
<button @click="count++">+1</button>
在日常开发中,你看到的基本都是简写形式,前者基本只出现在教学示例中。
3. 向事件处理器传递参数
如果需要在触发事件时传入自定义参数,直接在模板中调用即可:
<template>
<div>{{ count }}</div>
<button @click="add('Hello World')">+1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function add(message) {
count.value++;
console.log(message);
}
</script>
4. 事件对象
这是一个比较容易踩坑的点。Vue 中事件对象的获取方式取决于是否传参:
没有传参时,事件对象会自动作为第一个参数传入:
<template>
<div>{{ count }}</div>
<button @click="add">+1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
// 事件对象自动传入,形参中声明即可
function add(event) {
count.value++;
console.log(event);
console.log(event.target);
console.log(event.clientX, event.clientY);
}
</script>
有传参时,需要通过特殊的 $event 变量显式传递事件对象:
<template>
<div>{{ count }}</div>
<button @click="add('Hello World', $event)">+1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function add(message, event) {
count.value++;
console.log(message);
console.log(event);
console.log(event.target);
console.log(event.clientX, event.clientY);
}
</script>
如果是箭头函数,写法更加灵活,参数名不限于 $event:
<template>
<div>{{ count }}</div>
<button @click="(event) => add('Hello World', event)">+1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function add(message, event) {
count.value++;
console.log(message);
console.log(event);
}
</script>
最佳实践:简单场景用 $event,复杂场景用箭头函数包裹更灵活。
事件修饰符
Q: 什么是事件修饰符?为什么需要它们?
A: 在原生 JS 的事件处理中,我们经常需要在处理函数里写 event.preventDefault() 阻止默认行为,或者 event.stopPropagation() 阻止冒泡。这些「非业务逻辑」的代码和真正的业务逻辑混在一起,让代码不够纯粹。Vue 提供了事件修饰符来解决这个问题,让事件处理器只关注业务本身。
常见的事件修饰符:
| 修饰符 | 作用 |
|---|---|
.stop |
阻止事件冒泡 |
.prevent |
阻止默认行为 |
.self |
只在元素本身触发(不在子元素上) |
.capture |
在捕获阶段触发(而非冒泡阶段) |
.once |
事件只触发一次 |
.passive |
提升页面滚动性能 |
使用也非常简单,在事件名后通过 . 连接即可:
<button @click.stop="handleClick">点击我</button>
一个具体示例——只触发一次的事件:
<template>
<button @click.once="clickHandle">click</button>
</template>
<script setup>
function clickHandle() {
console.log('你触发了事件');
}
</script>
修饰符可以连用。例如,需要一个按钮同时满足:阻止冒泡、阻止默认行为、捕获阶段触发、只触发一次:
<button @click.capture.stop.prevent.once>click</button>
修饰符的顺序通常不影响最终行为,因为不同的修饰符控制不同方面的行为,相互不冲突。
按键修饰符
除了事件修饰符,Vue 还提供了一组按键修饰符,用于快速检查特定的按键:
.enter/.tab/.delete(捕获 Delete 和 Backspace)/.esc/.space.up/.down/.left/.right.ctrl/.alt/.shift/.meta(不同系统对应不同按键)
<template>
<input type="text" @keyup.enter="submitText" />
</template>
<script setup>
function submitText() {
console.log('你要提交输入的内容');
}
</script>
按键修饰符也支持连用。例如,需要 Alt + Enter 才触发提交:
<input type="text" @keyup.alt.enter="submitText" />
Mac 系统中,
.alt对应的是 Option 按键。
.exact 精确修饰符
.exact 修饰符的作用是「精确匹配」——触发事件时,必须是指定的按键组合,不能有其他按键。
<button @click.ctrl="onClick">A</button>
<button @click.ctrl.exact="onClick">A</button>
鼠标按键修饰符
最后还有三个鼠标按键修饰符:.left、.right、.middle。
<template>
<button
class="context-menu-button"
@contextmenu.prevent.right="handleRightClick"
>
右键点击
</button>
</template>
<script setup>
function handleRightClick() {
console.log('你点击了鼠标右键');
}
</script>
上面的例子用到了修饰符连用——.prevent 阻止默认的右键菜单弹出,.right 指定仅响应鼠标右键。
表单双向绑定
Q: v-model 是怎么实现双向绑定的?它和手动绑定有什么区别?
A: 先看一个手动实现双向绑定的例子:
<template>
<input
type="text"
:value="textContent"
@input="(e) => (textContent = e.target.value)"
/>
<p>你当前输入的内容为:{{ textContent }}</p>
</template>
<script setup>
import { ref } from 'vue';
const textContent = ref('');
</script>
上面的代码通过 :value 将数据绑定到文本框,再通过 @input 事件将用户输入同步回数据——这就是双向绑定的本质。但这样写太繁琐了,每种表单元素都要记住对应的事件和属性。于是 Vue 提供了 v-model,一行搞定:
<template>
<input type="text" v-model="textContent" />
<p>你当前输入的内容为:{{ textContent }}</p>
</template>
<script setup>
import { ref } from 'vue';
const textContent = ref('');
</script>
v-model 的好处不止于简化书写,更智能的是它能根据表单元素类型自动选择合适的事件和属性组合:
| 表单元素 | 绑定事件 | 绑定属性 |
|---|---|---|
| input / textarea | input |
value |
| checkbox / radio | change |
checked |
| select | change |
value |
各种表单元素的 v-model 用法
文本域(textarea):
<template>
<textarea cols="30" rows="10" v-model="textContent"></textarea>
<p>你当前输入的内容为:{{ textContent }}</p>
</template>
<script setup>
import { ref } from 'vue';
const textContent = ref('');
</script>
单个复选框——绑定布尔值,true 表示选中,false 表示未选中:
<template>
<input type="checkbox" v-model="checked" />
<button @click="checked = !checked">切换选中</button>
</template>
<script setup>
import { ref } from 'vue';
const checked = ref(true);
</script>
也可以通过 :true-value 和 :false-value 自定义真假值:
<template>
<input
type="checkbox"
v-model="checked"
:true-value="customTrue"
:false-value="customFalse"
/>
<button @click="toggle">切换选中</button>
</template>
<script setup>
import { ref } from 'vue';
const checked = ref('yes');
// yes 表示选中,no 表示未选中
const customTrue = ref('yes');
const customFalse = ref('no');
function toggle() {
checked.value === 'yes' ? (checked.value = 'no') : (checked.value = 'yes');
}
</script>
多个复选框——绑定到同一个数组,被选中的复选框的值会自动加入数组:
<template>
<div v-for="(item, index) in arr" :key="index">
<label :for="item.id">{{ item.title }}</label>
<input type="checkbox" v-model="hobby" :id="item.id" :value="item.value" />
</div>
<p>{{ message }}</p>
</template>
<script setup>
import { ref, computed } from 'vue';
const hobby = ref([]);
const arr = ref([
{ id: 'swim', title: '游泳', value: '游个泳' },
{ id: 'run', title: '跑步', value: '跑个步' },
{ id: 'game', title: '游戏', value: '玩个游戏' },
{ id: 'music', title: '音乐', value: '听个音乐' },
{ id: 'movie', title: '电影', value: '看个电影' },
]);
const message = computed(() => {
if (hobby.value.length === 0) return '请选择爱好';
else return `您选择了${hobby.value.join('、')}`;
});
</script>
单选框(radio):
<template>
<label for="male">男</label>
<input type="radio" id="male" v-model="gender" value="男" />
<label for="female">女</label>
<input type="radio" id="female" v-model="gender" value="女" />
<label for="secret">保密</label>
<input type="radio" id="secret" v-model="gender" value="保密" />
</template>
<script setup>
import { ref } from 'vue';
const gender = ref('保密');
setTimeout(() => {
gender.value = '男';
}, 3000);
</script>
哪个单选框被选中,取决于 gender 的值与哪个 value 匹配。
下拉列表(select)——v-model 写在 select 上,根据单选/多选绑定不同类型:
<template>
<select v-model="hometown1">
<option value="" disabled>请选择</option>
<option
v-for="(item, index) in hometownList"
:key="index"
:value="item.key"
>
{{ item.value }}
</option>
</select>
<p>您选择的家乡为:{{ hometown1 }}</p>
<select v-model="hometown2" multiple>
<option value="" disabled>请选择</option>
<option
v-for="(item, index) in hometownList"
:key="index"
:value="item.key"
>
{{ item.value }}
</option>
</select>
<p>您选择的家乡为:{{ hometown2 }}</p>
</template>
<script setup>
import { ref } from 'vue';
const hometown1 = ref('');
const hometown2 = ref([]);
const hometownList = ref([
{ key: '成都', value: '成都' },
{ key: '帝都', value: '北京' },
{ key: '魔都', value: '上海' },
{ key: '妖都', value: '广州' },
{ key: '陪都', value: '重庆' },
]);
</script>
关键点:单选绑定字符串,多选绑定数组。
表单修饰符
Q: v-model 有哪些实用的修饰符?
A: Vue 为 v-model 提供了三个常用的修饰符:
| 修饰符 | 作用 |
|---|---|
.lazy |
改由 change 事件触发更新(默认是 input) |
.number |
自动将输入转为 number 类型 |
.trim |
自动去除输入首尾空格 |
<template>
<input type="text" v-model.lazy="mess1" />
<p>你输入的是:{{ mess1 }}</p>
<input type="text" v-model.number="mess2" />
<p>你输入的是:{{ mess2 }}</p>
<p>类型为{{ typeof mess2 }}</p>
<input type="text" v-model.trim="mess3" />
<p>你输入的是:{{ mess3 }}</p>
</template>
<script setup>
import { ref } from 'vue';
const mess1 = ref('');
const mess2 = ref('');
const mess3 = ref('');
</script>
这三个修饰符覆盖了表单开发中最常见的需求——同步时机控制、类型转换、空白处理,比手动在事件处理函数中写这些逻辑要简洁太多。
小结
本文覆盖了 Vue3 中事件处理与表单绑定的核心知识点:
- 事件绑定:
v-on(简写@)绑定事件,支持内联处理器、方法处理器、参数传递。事件对象在无参时自动传入,有参时通过$event或箭头函数传递。 - 事件修饰符:
.stop、.prevent、.once、.capture、.self、.passive将非业务逻辑从处理函数中剥离,修饰符支持链式连用。 - 按键修饰符:
.enter、.alt、.ctrl等可快速检测按键组合,.exact实现精确匹配。 - v-model 双向绑定:自动根据表单元素类型选择正确的事件和属性组合。复选框(数组绑定多选)、单选框、下拉列表(单选字符串/多选数组)各有特定用法。
- 表单修饰符:
.lazy控制更新时机、.number类型转换、.trim去空格,覆盖常见表单处理需求。
掌握这些技能后,处理用户交互和表单将变得非常高效。