vue3-指令和事件处理

指令(Directives)是 Vue 模板中最具标志性的功能,它们以 v- 开头,本质上是模板语法糖------让你在 HTML 中直接操作 DOM 状态。

结合你目前的项目(<script setup> + TypeScript),我把 Vue 3 最核心的指令和事件处理分成 "数据渲染""条件/循环""事件/表单""高级性能" 四大板块来讲,重点拆解你在实战中最容易踩坑的地方。


1. 数据渲染:v-bind(动态属性)与 v-html

v-bind(简写 :

这是最常用的指令,用来动态绑定 HTML 属性。

复制代码
<script setup lang="ts">
const imgUrl = 'https://example.com/logo.png'
const isDisabled = true
const customId = 'main-box'
</script>

<template>
  <!-- 标准写法 -->
  <img v-bind:src="imgUrl" />
  <!-- 简写(99% 的情况都这么写) -->
  <img :src="imgUrl" />
  
  <!-- 动态绑定布尔值属性 -->
  <button :disabled="isDisabled">不可点击</button>
  
  <!-- 动态绑定多个属性(直接传入对象) -->
  <div :id="customId" :class="{ active: isActive }"></div>
</template>

💡 动态参数(高级)v-bind:[attributeName]="value",属性名本身可以是 JS 表达式。

v-html(谨慎使用)

用于插入原始 HTML 片段(会覆盖子元素)。

复制代码
<template>
  <div v-html="rawHtml"></div>
</template>

⚠️ 安全警告千万不要 在用户输入的内容上使用 v-html,极易导致 XSS 攻击。只用于你完全可控的富文本数据。


2. 条件渲染:v-if vs v-show

指令 原理 适用场景
v-if "真实销毁/重建" 。若为 false,该元素及其事件监听器不会存在于 DOM 中。 初始渲染条件不确定,或切换成本较高(如复杂的组件)。
v-show "CSS 显隐" 。元素始终存在,只是切换 display: none 频繁切换显示/隐藏(如下拉菜单、Tab 切换)。
复制代码
<template>
  <!-- v-if 配套 v-else-if / v-else -->
  <div v-if="status === 'loading'">加载中...</div>
  <div v-else-if="status === 'error'">出错了</div>
  <div v-else>内容加载完毕</div>

  <!-- v-show 不支持 v-else -->
  <div v-show="isVisible">我频繁切换,用 v-show 更省性能</div>
</template>

3. 🚀 列表渲染:v-for(高频考点)

v-for 用于遍历数组或对象。必须搭配 :key,这是 Vue 进行虚拟 DOM 对比(Diff 算法)的唯一标识。

遍历数组(最常用)
复制代码
<script setup lang="ts">
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
]
</script>

<template>
  <!-- (item, index) 两个参数 -->
  <li v-for="(user, index) in users" :key="user.id">
    {{ index + 1 }} - {{ user.name }}
  </li>
</template>
遍历对象
复制代码
<template>
  <li v-for="(value, key, index) in myObject" :key="key">
    {{ key }}: {{ value }}
  </li>
</template>
遍历数字范围
复制代码
<template>
  <span v-for="n in 10" :key="n">{{ n }}</span> <!-- 输出 1 到 10 -->
</template>

4. ⚠️ 致命陷阱:v-forv-if 的优先级

在 Vue 3 中,v-if 的优先级高于 v-for

这意味着,如果你在同一个元素上同时写这两个指令,v-if 无法访问 v-for 作用域里的变量(因为 v-if 先执行,此时循环变量还不存在)。

❌ 错误写法(会报错)

复制代码
<!-- 报错:item 在 v-if 中未定义 -->
<li v-for="item in list" v-if="item.isActive" :key="item.id">{{ item.name }}</li>

✅ 正确写法(使用 <template> 包装)

复制代码
<template v-for="item in list" :key="item.id">
  <li v-if="item.isActive">{{ item.name }}</li>
</template>

更推荐的写法是使用计算属性先过滤数据,这样模板更干净、性能更好。


5. 事件处理:v-on(简写 @

这是你代码里 @update="handleChildEmit" 的底层原理。

基本用法与传参
复制代码
<script setup lang="ts">
// TypeScript 类型注解:事件对象是 MouseEvent
const handleClick = (event: MouseEvent) => {
  console.log(event.clientX)
}

const handleSubmit = (msg: string, event: MouseEvent) => {
  console.log(msg, event.target)
}
</script>

<template>
  <!-- 1. 不传参,默认接收原生事件对象 -->
  <button @click="handleClick">点击</button>

  <!-- 2. 传参 + 保留原生事件对象(必须用 $event 占位) -->
  <button @click="handleSubmit('Hello', $event)">传参点击</button>
</template>
事件修饰符(非常实用,减少 JS 代码量)
修饰符 作用 示例
.stop 阻止事件冒泡(event.stopPropagation() @click.stop="doThis"
.prevent 阻止默认行为(event.preventDefault() @submit.prevent="onSubmit"
.once 事件只触发一次 @click.once="doOnce"
.self 只有 event.target 是自身时才触发 @click.self="doThat"
.capture 事件监听器使用捕获模式

链式调用@click.stop.prevent="doIt"(阻止冒泡并阻止默认行为)。

按键修饰符(键盘事件)
复制代码
<!-- 只有按下 Enter 键才触发 -->
<input @keyup.enter="submit" />
<!-- 只有按下 Ctrl + S 触发 -->
<input @keyup.ctrl.s="save" />

6. 双向绑定 v-model 的进阶(修饰符)

你在代码中使用了 v-model="modelValue",这里补充 3 个修饰符:

修饰符 作用
.lazy input 事件改为 change 事件(失焦时再更新,提升大文本输入性能)
.number 自动将用户输入转为数字类型
.trim 自动过滤首尾空格
复制代码
<template>
  <input v-model.number="age" type="number" />
  <input v-model.trim="username" />
</template>

7. 性能优化:v-oncev-memo

  • v-once:渲染一次后,该元素及其子元素不再随数据变化而更新(适合静态内容)。

    复制代码
    <div v-once>{{ 巨大的静态数据 }}</div>
  • v-memo(Vue 3.2+):缓存特定依赖项的渲染结果,只有依赖项变化时才重新渲染。

    复制代码
    <div v-memo="[item.id, item.name]">
      <!-- 只有 item.id 或 item.name 变化时才更新 -->
    </div>

8. 在你当前代码中的实际映射

回顾你的 父组件 模板,你已经用了:

  • v-model="modelValue":双向绑定。
  • @update="handleChildEmit" :事件处理(v-on 简写)。
  • @click="callChildMethod":点击事件传参。

你可以尝试将 v-for 加入练习,比如在父组件中加一个数组:

复制代码
const demoList = ref(['Vue', 'React', 'Angular'])

然后在模板里用 v-for 渲染,观察加上 :key 和不加的区别(打开浏览器控制台看 Vue 的警告)。


总结速记口诀(帮你记忆)

  • 属性绑定:事件绑定@
  • v-if 切成本高v-show 切频繁
  • v-for 必带 :key不要与 v-if 同行
  • 事件修饰符链式写$event 传原生对象

如果有哪个指令你觉得自己还没完全摸透,或者想让我结合某个具体业务场景(比如表格渲染、表单验证)再展开讲讲,随时告诉我! 😄

相关推荐
风骏时光牛马1 小时前
AI助手异常问题Debug排查
前端
mqiqe1 小时前
AgentScope Java Harness:2. 上下文压缩:让长期 Agent 永不“失忆“
java·开发语言
Aurorar0rua1 小时前
CS50 x 2024 Notes Memory - 03
c语言·开发语言·学习方法
梦想的旅途21 小时前
企业微信API实战:Python自动化消息推送
java·前端·python·自动化·企业微信
恋猫de小郭1 小时前
Flutter 3.47 发布,快来看看有什么更新吧
android·前端·flutter
程序员黑豆1 小时前
Java 内存存储机制:基本数据类型 vs 引用数据类型
前端·ai编程·全栈
爱敲代码的憨仔2 小时前
BM25全文检索
开发语言·python·全文检索
90后的晨仔2 小时前
uni-app 三方库与插件管理体系全解析:从原生开发者视角彻底讲透
前端
程序员爱钓鱼2 小时前
Rust 生命周期案例详解:从编译错误到真实业务场景
前端·后端·rust