当前位置: 首页 > article >正文

详细讲一下Vue3中的Transition组件用法(动画)

1. 基础过渡动画

<template>
  <!-- 
    transition 组件是 Vue 提供的内置组件
    name 属性定义了过渡类名的前缀
  -->
  <transition name="fade">
    <div v-if="show" class="box">Hello</div>
  </transition>
</template>

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

<style>
/* 进入和离开的过渡状态 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

/* 进入前和离开后的状态 */
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

/* 进入后和离开前的状态 */
.fade-enter-to,
.fade-leave-from {
  opacity: 1;
}
</style>

2. 自定义过渡类名

<template>
  <!-- 
    使用自定义类名,可以配合第三方动画库使用
    比如 Animate.css
  -->
  <transition
    enter-active-class="animate__animated animate__fadeIn"
    leave-active-class="animate__animated animate__fadeOut"
  >
    <div v-if="show">自定义动画</div>
  </transition>
</template>

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

3. 过渡动画钩子

<template>
  <transition
    @before-enter="onBeforeEnter"
    @enter="onEnter"
    @after-enter="onAfterEnter"
    @before-leave="onBeforeLeave"
    @leave="onLeave"
    @after-leave="onAfterLeave"
  >
    <div v-if="show" class="box">动画钩子</div>
  </transition>
</template>

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

// 进入过渡前
const onBeforeEnter = (el) => {
  el.style.opacity = 0
}

// 进入过渡中
const onEnter = (el, done) => {
  // 触发回流,使动画生效
  el.offsetHeight
  el.style.opacity = 1
  // 动画完成时调用 done
  done()
}

// 进入过渡后
const onAfterEnter = (el) => {
  console.log('进入完成')
}

// 离开过渡前
const onBeforeLeave = (el) => {
  el.style.opacity = 1
}

// 离开过渡中
const onLeave = (el, done) => {
  el.style.opacity = 0
  done()
}

// 离开过渡后
const onAfterLeave = (el) => {
  console.log('离开完成')
}
</script>

4. 列表过渡

<template>
  <!-- 
    transition-group 用于列表过渡
    tag 指定渲染的元素
  -->
  <transition-group 
    name="list" 
    tag="ul"
  >
    <li 
      v-for="item in items" 
      :key="item.id"
      class="list-item"
    >
      {{ item.text }}
    </li>
  </transition-group>
</template>

<script setup>
import { ref } from 'vue'

const items = ref([
  { id: 1, text: '项目 1' },
  { id: 2, text: '项目 2' },
  { id: 3, text: '项目 3' }
])

// 添加项目
const addItem = () => {
  items.value.push({
    id: items.value.length + 1,
    text: `项目 ${items.value.length + 1}`
  })
}

// 删除项目
const removeItem = (index) => {
  items.value.splice(index, 1)
}
</script>

<style>
/* 列表项的基础样式 */
.list-item {
  display: inline-block;
  margin-right: 10px;
}

/* 进入和离开的过渡 */
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}

/* 移动过渡 */
.list-move {
  transition: transform 0.5s ease;
}

/* 进入前和离开后的状态 */
.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}
</style>

5. 状态过渡

<template>
  <div>
    <!-- 数字动画 -->
    <div class="number">
      {{ animatedNumber }}
    </div>
    
    <!-- 颜色动画 -->
    <div 
      class="color-block"
      :style="{ backgroundColor: color }"
    ></div>
  </div>
</template>

<script setup>
import { ref, reactive, watch } from 'vue'
import gsap from 'gsap'

// 数字动画
const number = ref(0)
const animatedNumber = ref(0)

watch(number, (newValue) => {
  gsap.to(animatedNumber, {
    duration: 1,
    value: newValue
  })
})

// 颜色动画
const color = ref('#42b883')

const changeColor = () => {
  color.value = color.value === '#42b883' ? '#35495e' : '#42b883'
}
</script>

<style>
.color-block {
  width: 100px;
  height: 100px;
  transition: background-color 1s;
}
</style>

6. 可复用的过渡组件

<!-- src/components/FadeTransition.vue -->
<template>
  <transition
    name="custom-fade"
    :duration="duration"
    v-bind="$attrs"
  >
    <slot></slot>
  </transition>
</template>

<script setup>
defineProps({
  duration: {
    type: [Number, Object],
    default: 300
  }
})
</script>

<style>
.custom-fade-enter-active,
.custom-fade-leave-active {
  transition: opacity 0.3s ease;
}

.custom-fade-enter-from,
.custom-fade-leave-to {
  opacity: 0;
}
</style>

<!-- 使用方式 -->
<template>
  <FadeTransition :duration="500">
    <div v-if="show">内容</div>
  </FadeTransition>
</template>

7. 路由过渡

<!-- App.vue -->
<template>
  <router-view v-slot="{ Component }">
    <transition 
      name="route" 
      mode="out-in"
    >
      <component :is="Component" />
    </transition>
  </router-view>
</template>

<style>
.route-enter-active,
.route-leave-active {
  transition: opacity 0.5s ease;
}

.route-enter-from,
.route-leave-to {
  opacity: 0;
}
</style>

8. 组合动画示例

<template>
  <div class="container">
    <transition
      name="modal"
      @before-enter="onBeforeEnter"
      @enter="onEnter"
      @leave="onLeave"
    >
      <div v-if="show" class="modal">
        <div class="modal-content">
          <h2>标题</h2>
          <p>内容</p>
          <button @click="show = false">关闭</button>
        </div>
      </div>
    </transition>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import gsap from 'gsap'

const show = ref(false)

// 进入前
const onBeforeEnter = (el) => {
  el.style.opacity = 0
  const content = el.querySelector('.modal-content')
  content.style.transform = 'scale(0.8)'
}

// 进入中
const onEnter = (el, done) => {
  // 背景淡入
  gsap.to(el, {
    duration: 0.3,
    opacity: 1
  })
  
  // 内容缩放
  const content = el.querySelector('.modal-content')
  gsap.to(content, {
    duration: 0.3,
    scale: 1,
    onComplete: done
  })
}

// 离开
const onLeave = (el, done) => {
  // 背景淡出
  gsap.to(el, {
    duration: 0.3,
    opacity: 0
  })
  
  // 内容缩放
  const content = el.querySelector('.modal-content')
  gsap.to(content, {
    duration: 0.3,
    scale: 0.8,
    onComplete: done
  })
}
</script>

<style scoped>
.modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-content {
  background: white;
  padding: 20px;
  border-radius: 8px;
  transform-origin: center;
}
</style>

这些示例涵盖了 Vue3 中动画的主要使用场景。记住:

  • 使用 transition 组件处理单元素/组件过渡
  • 使用 transition-group 处理列表过渡
  • 可以使用 JavaScript 钩子实现复杂动画
  • 考虑使用第三方动画库增强效果
  • 注意性能优化和动画的适用场景

http://www.kler.cn/a/459839.html

相关文章:

  • MLP、CNN、Transformer 的区别解析
  • Colyseus 与 HTTP API 的集成
  • html 音频和视频组件
  • 【代码】Python|Windows 批量尝试密码去打开加密的 Word 文档(docx和doc)
  • 如果Adobe 退出中国后怎么办
  • UE4.27 Android环境下获取手机电量
  • 嵌入式从入门到入土:C语言3(运算符、顺序结构、分支结构)
  • uni-app组件间传值
  • Tailwind CSS 实战:现代登录注册页面开发
  • 优优嗨聚集团:个人债务安全,走向财务自由的智慧之路
  • 嵌入式单片机中蓝牙模块的详解
  • vue2使用tailwindcss
  • 地理数据库Telepg面试内容整理-描述你如何在GIS应用中使用空间数据进行分析并生成可视化结果
  • nvidia_gpu_exporter 显卡监控
  • 基于python大数据的体育用品营销支撑系统研究
  • Vue.js组件开发-实现列表无缝动态滚动
  • Kafka 幂等性与事务
  • VIM: Vision Mamba基于双向状态空间模型的高效视觉表示学习
  • STM32完全学习——FLASH上FATFS文件管理系统
  • OpenHarmony源码编译后烧录镜像教程,RK3566鸿蒙开发板演示
  • 本地创建了一个 Git 仓库推送到GitHub中
  • Android笔试面试题AI答之非技术问题(2)
  • OPPO手机如何正确使用金融理财计算器
  • vue3学习笔记(11)-组件通信
  • XL系列433芯片、2.4G收发芯片 通讯对码说明
  • 【LeetCode 面试经典150题】详细题解之矩阵篇