Vue3 笔记:过渡动画与自定义指令

近期重点复盘了 Vue3 的部分知识点,主要是过渡动画自定义指令两大模块。其中自定义指令在实际开发中(如防抖、节流)高频使用,该篇主要讲解;过渡动画则是提升用户体验的基础,也会结合案例梳理核心逻辑。

一、Vue3 过渡动画(transition 组件)(⭐)

在 Vue 中,transition 是内置的过渡动画组件,能为元素的插入/移除(如v-if/v-show 控制)添加流畅的动画效果,核心是通过预设的 CSS 类名控制动画的**[进入/离开]**状态。

1. 核心原理

transition 组件会在元素进入 / 离开 DOM 时,自动为元素添加 / 移除一系列以[动画名称]为前缀的 CSS 类名,我们只需通过这些类名定义动画的起始、过程、结束状态。

核心 CSS 类名(以**name="fade"**为例):

类名 作用
fade-enter-from 进入动画的初始状态(进入前)
fade-enter-active 进入动画的执行状态(进入中)
fade-enter-to 进入动画的结束状态(进入后)
fade-leave-from 离开动画的初始状态(离开前)
fade-leave-active 离开动画的执行状态(离开中)
fade-leave-to 离开动画的结束状态(离开后)

2. 实战案例:元素显隐动画

TypeScript 复制代码
<template>
  <div>
    <button @click="visible = !visible">显示/隐藏</button>
    <!-- appear:控制初始渲染时也触发动画 -->
    <transition appear name="fade">
      <div class="box" v-if="visible"></div>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(true) // 控制元素显隐
</script>

<style scoped>
.box {
  width: 200px;
  height: 200px;
  background-color: rgb(178, 147, 147);
}

/* 进入的初始状态/离开的最终状态 */
.fade-enter-from {
  opacity: 0; /* 透明 */
  transform: translateX(-20px); /* 左移20px */
}
.fade-leave-to {
  opacity: 0; /* 透明 */
  transform: translateX(20px); /* 右移20px */
} 

/* 动画执行过程(缓动效果) */
.fade-enter-active, .fade-leave-active {
  transition: all 0.5s ease;
}

/* 进入的最终状态/离开的初始状态 */
.fade-enter-to, .fade-leave-from {
  opacity: 1; /* 不透明 */
  transform: translateX(0); /* 回到原位置 */
}
</style>

代码所示这种效果当你点击按钮,box从显性---->隐身时会有一个消失动画,box会向右缓动平移20px的距离消失

小结

  • **appear**属性让元素初始渲染时也触发动画;
  • 动画的核心是「状态切换」,通过 CSS 过渡属性 transition 控制动画时长和缓动效果;
  • transition 仅包裹单个元素,若需多个元素 / 组件过渡,可使用 transition-group

二、Vue3 自定义指令(⭐⭐⭐⭐⭐)

Vue 内置指令(如v-if,v-bind)满足日常开发,但实际场景中(防抖、节流、图片懒加载等)需要自定义指令封装通用逻辑。Vue3 中自定义指令分为「局部指令」和「全局指令」,接下来以「全局防抖指令 v-debounce」为例拆解。

1. 自定义指令的核心概念

自定义指令本质是一个包含生命周期钩子的对象,核心钩子包括:

  • mounted:指令绑定到元素且元素挂载到 DOM 时触发(常用);
  • beforemount:指令绑定的元素卸载前触发(用于清理定时器 / 事件监听);
指令钩子的核心参数(⭐⭐⭐):

el:指令绑定的DOM 元素(可直接操作 DOM,如添加事件监听、修改样式);

binding:指令的[信息对象],包含:

  • arg :指令参数(如 v-debounce:1000 中的 1000);
  • value :指令绑定的值(如 v-debounce="clickHandler" 中的 clickHandler);
  • modifiers :指令修饰符(如 v-debounce.stop 中的 stop);

下文有二者的输出可更有益于理解二者

2. 实战:全局防抖指令**v-debounce**

2.1 需求背景

按钮点击时若频繁触发事件(如提交表单),会增加服务器压力,通过防抖指令限制[n 毫秒内仅执行一次点击事件]

2.2 全局注册自定义指令(main.ts)
TypeScript 复制代码
import { createApp } from 'vue'
import App from './study_tree/组件化开发/19.内置组件/30.自定义指令.vue'

const app = createApp(App)

// 全局注册 v-debounce 指令
app.directive('debounce', {
  //查看二者详情  
  console.log("el", el, "binding", binding);

  // 指令绑定元素并挂载后触发
  mounted(el: HTMLElement, binding) {
    let timer = null // 存储定时器ID
    // 防抖时间:优先取指令参数(如v-debounce:1000),默认500ms
    const timeout = binding.arg || 500

    // 为元素添加点击事件监听
    el.addEventListener('click', () => {
      // 若已有定时器,清除(重置防抖计时)
      if (timer) clearTimeout(timer)
      // 延迟执行绑定的事件处理函数
      timer = setTimeout(binding.value, timeout)
    })

    // 示例:给元素挂载定时器(仅演示,实际防抖无需)
    el.timer = setInterval(() => {
      console.log('定时器示例')
    }, 1000)
  },

  // 元素卸载前清理资源(避免内存泄漏)
  beforeUnmount(el: HTMLElement) {
    // 清除定时器
    clearTimeout(el.timer)
    // 移除事件监听(避免重复触发)
    el.removeEventListener('click', el.clickHandler)
  }
})

app.mount('#app')
2.3 使用自定义指令(组件中)
TypeScript 复制代码
<template>
  <div>
    <button @click="visible = !visible">切换可见性</button>
    <button @click="clickHandler">不带防抖</button>
    <!-- 使用v-debounce,参数1000表示防抖1秒 -->
    <button v-debounce:1000="clickHandler" v-if="visible">带防抖 1s</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const visible = ref(true)
// 点击事件处理函数
function clickHandler() {
  console.log("点击了按钮(防抖后执行)")
}
</script>

2.4 控制台截图

3. 核心逻辑拆解(⭐⭐⭐)

3.1 mounted钩子的防抖逻辑
  1. 初始化 **timer**存储定时器 ID,避免重复计时;
  2. 通过**binding.arg** 获取防抖时间(无参数则默认 500ms);
  3. 给元素绑定点击事件:
    • 若已有定时器,先清除(重置防抖);
    • 新建定时器,延迟 timeout 毫秒执行 binding.value(即绑定的点击函数)。
3.2 beforeUnmount 钩子的资源清理
  • 清除 el.timer(避免定时器残留导致内存泄漏);
  • 移除元素的点击事件监听(避免卸载后事件仍触发);
3.3 参数使用
  • el:直接操作 DOM 的入口,比如 el.addEventListener 绑定事件、el.timer 挂载自定义属性;
  • binding.arg:灵活传递防抖时间,比如 v-debounce:500 对应 500ms,v-debounce:1000 对应 1 秒;
  • binding.value:接收组件中传递的[事件处理函数],是指令和组件逻辑的桥梁。

三、 总结

  • 过渡动画:通过 transition 组件 + CSS 类名控制元素显隐动画,核心是[状态切换]和[过渡属性],**appear**属性解决初始渲染无动画问题;
  • 自定义指令:
    • 核心是[操作 DOM + 封装通用逻辑],mounted 钩子绑定逻辑,**beforeUnmount**钩子清理资源;
    • el 是操作 DOM 的入口,binding 是指令与组件通信的桥梁(arg 传参数、value 传回调);
    • 防抖指令是高频场景,需注意「定时器清理」避免内存泄漏。

这一节的内容需要动手+思考 理清思路,废话不多说,"动手吧"!

相关推荐
M ? A2 小时前
Vue Suspense 组件在 React 中,VuReact 会如何实现?
前端·javascript·vue.js·经验分享·react.js·面试·vureact
im_AMBER2 小时前
Leetcode 159 无重复字符的最长子串 | 长度最小的子数组
javascript·数据结构·学习·算法·leetcode
源码之家2 小时前
计算机毕业设计:Python农产品智能推荐与可视化分析系统 Flask框架 矩阵分解 数据分析 可视化 协同过滤推荐算法 深度学习(建议收藏)✅
python·矩阵·数据挖掘·数据分析·django·flask·课程设计
天才熊猫君2 小时前
通用 Loading 状态管理器
前端·javascript·vue.js
Betelgeuse762 小时前
打通 Django 认证:原生 Auth 组件实战与 API 改造
后端·python·django
RONIN2 小时前
vue插件--路由vue-router
vue.js
Ruihong2 小时前
Vue Suspense 组件在 React 中,VuReact 会如何实现?
vue.js·react.js·面试
m0_515098422 小时前
如何实现SQL数据分片规则更新_利用触发器同步元数据
jvm·数据库·python
qq_330037992 小时前
uni-app怎么实现App端蓝牙搜索与连接 uni-app低功耗蓝牙开发【代码】
jvm·数据库·python