Skip to content

✨ 事件处理 👌

快速入门

在 Vue 中使用 v-on(缩写为 @)为元素绑定事件:

vue
<template>
  <div>{{ count }}</div>
  <button v-on:click="add">+1</button>
  <button @click="add">+1(简写)</button>
</template>

<script setup>
import { ref } from "vue";
const count = ref(0);
function add() {
  count.value++;
}
</script>

书写建议

  • 常规写法使用方法引用(如 @click="add"),语义清晰且便于复用。
  • 简写 @ 是日常首选;根据团队规范统一风格即可。

处理器写法与传参

事件处理器可写为方法、内联表达式或箭头函数:

vue
<template>
  <div>{{ count }}</div>
  <!-- 方法引用 -->
  <button @click="add">+1</button>
  <!-- 内联表达式(逻辑极简单场景) -->
  <button @click="count++">+1</button>
  <!-- 传参调用 -->
  <button @click="addWithMsg('Hello World')">+1</button>
</template>

<script setup>
import { ref } from "vue";
const count = ref(0);
function add() {
  count.value++;
}
function addWithMsg(message) {
  count.value++;
  console.log(message);
}
</script>

可读性与性能

  • 复杂逻辑尽量写成方法,避免在模板内堆叠三元/长表达式。
  • 在大列表中避免为每项创建箭头函数,优先方法引用提升可读性和复用性。

事件对象与 $event

不传参时,原生事件对象会自动作为额外参数传入;传参时用 $event 显式传递:

vue
<template>
  <button @click="onClick">+1</button>
</template>

<script setup>
function onClick(event) {
  console.log(event.target, event.clientX, event.clientY);
}
</script>
vue
<template>
  <button @click="onClickWithMsg('Hello', $event)">+1</button>
</template>

<script setup>
function onClickWithMsg(message, event) {
  console.log(message, event.type);
}
</script>

箭头函数时直接接收事件对象:

vue
<template>
  <button @click="(e) => onClickWithMsg('Hello', e)">+1</button>
</template>

$event 的场景

当既要传自定义参数又要拿到原生事件对象时,使用 $event 传递更直观。

修饰符

修饰符用于处理非核心业务(阻止冒泡、阻止默认、捕获、一次性等),让处理器专注业务逻辑:

  • .stop:阻止事件冒泡
  • .prevent:阻止默认行为
  • .self:仅当事件在元素本身触发时才处理(非子元素)
  • .capture:在捕获阶段触发处理器
  • .once:事件只触发一次
  • .passive:提升滚动相关事件的性能
vue
<template>
  <div @click="parent">
    <button @click.stop="child">阻止冒泡</button>
    <form @submit.prevent="submit">阻止默认提交</form>
    <div class="overlay" @click.self="close">点击遮罩本身才关闭</div>
  </div>
</template>

<script setup>
function parent() {
  console.log("parent");
}
function child() {
  console.log("child");
}
function submit() {
  console.log("submitted");
}
function close() {
  console.log("closed");
}
</script>

关于 .passive

  • 在被标记为 passive 的监听器中调用 event.preventDefault() 将被忽略并触发控制台警告。
  • 适用于 touchstart/touchmovewheel 等滚动相关事件以提升性能。

修饰符连用

修饰符可连用,组合不同维度的行为控制:

vue
<button @click.capture.stop.prevent.once="handle">click</button>

<script setup>
function handle() {
  console.log("handled once in capture phase");
}
</script>

顺序影响

不同修饰符侧重点不同(传播、默认行为、阶段、次数),通常连用时顺序不影响最终结果。

按键修饰符

用于键盘事件的快捷判断:

  • .enter .tab .delete(含 Delete & Backspace) .esc .space
  • .up .down .left .right
  • 组合:.ctrl .alt .shift .meta
vue
<template>
  <input type="text" @keyup.enter="submitText" />
  <input type="text" @keyup.alt.enter="submitText" />
</template>

<script setup>
function submitText() {
  console.log("提交输入内容");
}
</script>

.meta 与平台

Windows/Linux 下为 Windows 键;macOS 为 Command 键。

精确匹配:.exact

要求仅在指定组合按下、且无其他按键参与时触发:

vue
<button @click.ctrl.exact="onClick">只在单独按下 Ctrl 时触发</button>

鼠标按键修饰符

指定特定的鼠标按键:.left .right .middle。右键示例:

vue
<template>
  <button
    class="context-menu-button"
    @contextmenu.prevent.right="handleRightClick"
  >
    右键点击
  </button>
</template>

<script setup>
function handleRightClick() {
  console.log("你点击了鼠标右键");
}
</script>

<style scoped>
.context-menu-button {
  padding: 10px 20px;
  cursor: context-menu;
  background-color: #f5f5f5;
  border: 1px solid #ccc;
  border-radius: 5px;
}
</style>

进阶:组件自定义事件(简述)

组件之间的事件通信使用 defineEmits

vue
<!-- 子组件 -->
<script setup>
const emit = defineEmits(["submit"]);
function onSubmit(payload) {
  emit("submit", payload);
}
</script>

<!-- 父组件 -->
<Child @submit="handleSubmit" />

区分场景

DOM 事件用 v-on/@;组件事件用 defineEmits + emit

小结

  • 优先使用方法引用绑定事件,逻辑简单时可用内联或箭头函数。
  • $event 用于在传参场景显式传递原生事件对象;箭头函数可直接接收事件对象。
  • 修饰符让处理器聚焦业务逻辑;滚动相关场景慎用 .passivepreventDefault
  • 按键与鼠标修饰符提升可读性;.exact 控制精确组合匹配。
  • 组件事件通过 defineEmits/emit 进行通信,与 DOM 事件区分使用。