Vue3 零基础每日笔记(017):事件处理进阶——$event、多事件与事件修饰符全家桶

一、前言

004 篇初识了 @click,但这只算入门。真实项目里的事件处理有一堆讲究:怎么拿到事件对象、一个元素怎么同时处理多个事件、阻止冒泡和默认行为不想再手写 e.preventDefault() 怎么办。本篇把这些一次补齐,核心是让代码量砍一半的事件修饰符

二、内联表达式与方法的边界

简单逻辑直接内联,超过一行就抽方法------这个边界要守住:

vue 复制代码
<template>
  <!-- ✅ 简单逻辑:内联一行搞定 -->
  <button @click="count++">内联:{{ count }}</button>

  <!-- ✅ 复杂逻辑:抽方法,可读性好 -->
  <button @click="increment">方法:{{ count }}</button>

  <!-- ❌ 内联塞一坨逻辑:能跑,但没人想维护 -->
  <button @click="count++; if (count > 10) { count = 0 }; logged++">地狱写法</button>
</template>

<script setup>
import { ref } from 'vue'
const count = ref(0)
const logged = ref(0)

function increment() {
  count.value++
}
</script>

三、传参与 $event:既要传参又要事件对象

方法需要额外参数,同时还想要原生事件对象,用**$event** 占位:

vue 复制代码
<template>
  <!-- 不传参:默认收到事件对象 -->
  <button @click="onClick">无参</button>

  <!-- 传自定义参数 -->
  <button @click="say('hi')">传参</button>

  <!-- 既传参又要事件对象:$event 固定代表原生事件 -->
  <button @click="say('hi', $event)">传参 + 事件</button>
</template>

<script setup>
function onClick(e) {
  console.log('事件对象:', e.target.textContent)
}

function say(word, e) {
  console.log(word, e && e.type)  // hi click
}
</script>

记住:$event 就是原生事件对象的"专用座位",写在哪个参数位置就传到哪。

四、一个元素绑多个事件:数组写法

同一个事件挂多个处理函数,用数组包起来:

vue 复制代码
<template>
  <button @click="[handlerOne, handlerTwo]">一箭双雕</button>
</template>

<script setup>
function handlerOne() { console.log('第一个') }
function handlerTwo() { console.log('第二个') }
</script>

五、事件修饰符:告别手写 e.stopPropagation()

先看没有修饰符的原生写法多啰嗦:

js 复制代码
function submit(e) {
  e.preventDefault()      // 阻止默认行为
  e.stopPropagation()     // 阻止冒泡
  // ...业务代码
}

Vue 把这些高频操作做成"后缀糖",直接跟在 @ 后面:

修饰符 作用 记忆
.stop 阻止冒泡 别吵到我爸
.prevent 阻止默认行为 a 不跳转、form 不提交
.once 只触发一次 一锤子买卖
.self 只有自己被点才触发 点我儿子不算点我
.capture 用捕获模式监听 先爸后子的反向流程
.passive 告诉浏览器不阻止默认行为 滚动性能优化

1. .stop------最常用,弹层场景

vue 复制代码
<template>
  <div class="mask" @click="close">
    <div class="dialog" @click.stop>点这里不会关闭弹窗</div>
  </div>
</template>

不加 .stop,点弹窗内部也会冒泡到遮罩导致关闭------加了就"隔断"。

2. .prevent------表单与链接

vue 复制代码
<template>
  <!-- 表单不刷新页面(配合后面 019 篇的提交) -->
  <form @submit.prevent="onSubmit">
    <input v-model="text" />
    <button>提交</button>
  </form>

  <a href="https://vuejs.org" @click.prevent>链接失效了</a>
</template>

3. .once------只来一次

vue 复制代码
<button @click.once="reward">领取奖励(只能点一次)</button>

4. 修饰符可以串联,顺序有意义:

vue 复制代码
<a @click.stop.prevent="doThat">又阻止冒泡又阻止默认</a>

六、综合实战:防误触弹窗

把 .stop / .self / .prevent / .once 全用上:

vue 复制代码
<template>
  <button @click="show = true">打开弹窗</button>

  <!-- .self:只有点遮罩本身才关(点内容区不算) -->
  <div v-if="show" class="mask" @click.self="show = false">
    <div class="dialog">
      <h3>确认操作</h3>
      <a href="https://example.com/pay" @click.prevent.once="pay">
        首次点击支付(阻止跳转 + 只生效一次)
      </a>
      <button @click="show = false">关闭</button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const show = ref(false)

function pay() {
  console.log('调起支付逻辑,页面不跳转')
}
</script>

<style scoped>
.mask {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex; align-items: center; justify-content: center;
}
.dialog {
  background: #fff; padding: 24px; border-radius: 8px;
}
</style>

三个细节品味:

  1. .self.stop 更优雅:点弹窗内容冒泡到遮罩,但因为"目标不是遮罩自己",不触发关闭------弹窗标准写法
  2. .prevent.once 串联:第一次点击走 pay 逻辑且不跳转,第二次起链接恢复默认行为(演示用,实际支付按钮该用 disabled)
  3. v-if 控制弹窗出生销毁(015 篇知识复用)

【截图位置:点击遮罩关闭、点击内容区不关闭的运行效果】

七、踩坑记录

  1. @click="fn()" 与 @click="fn":带括号是"模板解析时求值后的调用时机控制",不带括号默认第一参数是事件对象;带括号还想拿事件对象必须显式传 $event(004 篇坑的完整版答案)
  2. .stop 和 .self 混淆:.stop 是"我不让往上冒",.self 是"不是点我就不理"------弹窗用 .self,按钮防冒泡用 .stop
  3. 修饰符顺序@click.prevent.self 会阻止所有点击 的默认行为(包括子元素);@click.self.prevent 只阻止"点自己"时的默认行为------顺序不同语义不同
  4. Vue3 移除了 .native 修饰符:Vue2 给组件根元素绑原生事件要 .native,Vue3 交给 attrs 透传机制(033 篇细讲),现在直接写会警告
  5. passive 别乱加@scroll.passive 提升滚动性能,但加了就不能在里面 e.preventDefault() 了

八、今日小结

  • $event 是原生事件对象的专用占位,传参与事件对象共存
  • 多个同事件处理器用数组:@[a, b]
  • 三大高频修饰符:.stop 防冒泡、.prevent 防默认、.once 一次性
  • 弹窗遮罩标准姿势:@click.self;修饰符可串联且顺序有语义

下篇预告

点击说完了,键盘怎么办?"按回车就搜索""按 Esc 关弹窗""Ctrl+S 保存"------下一篇 018 按键与鼠标修饰符,让键盘事件优雅到飞起。

相关推荐
阿洛学长1 小时前
Python笔记:dir() 和 help() 完整用法(适配Python二级 + IDLE实操)
服务器·笔记·python
光影少年1 小时前
react navite浏览器 Event Loop 和 Node Event Loop 的区别
前端·javascript·react native·react.js·前端框架
qeen871 小时前
【C++】智能指针介绍
开发语言·c++·笔记·指针
蒸蒸yyyyzwd4 小时前
cpp 选手秋招学习笔记 day33
c++·笔记·求职招聘
Bs_MoneyMagnet11 小时前
基于springboot+vue的医疗健康便民服务平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
Sunshing1514 小时前
Lyapunov方程系统本身稳定性判定与镇定性判定
笔记·学习
bug总结14 小时前
uniapp vue3全局方法注册使用
前端·javascript·uni-app
华无丽言14 小时前
如何在宜搭中实现获取子表中的字段值赋值到父表中?
前端·javascript·低代码
透明的玻璃杯15 小时前
热键驱动 Hotkey Features Integration v9.x(14MB)
笔记