vue3之transition动画组件

    <transition name="fade">
      <div v-if="flag2" class="box">我是动画啊</div>
    </transition>
  • 动画组件
  • 就是使用 transition 组件,然后使用 name的定义 传递进入组件动画的类名等样式
  • 触发机制
    • v-if
    • v-show
    • 动态组件等
  • 过渡的类名
    • 再进入与离开这个阶段之中,涉及到6个class类名的操作(eg: 再过度组件之中 name=“fade” 设置为 fade , 那么其类名 则是以 .fade-enter-from等类似 fade开头 )
    • v-enter-from:定义进入过渡的开始状态。
    • v-enter-active:定义进入过渡时,这个过程生效的状态。定义一些曲线、延迟等。
    • v-enter-to:定义进入过渡的结束状态。
    • v-leave-from:定义离开过渡的开始状态。
    • v-leave-active:定义离开过渡时,这个过程生效的状态。
    • v-leave-to:离开过渡的结束状态。

一个简单的过度效果 淡入淡出

<template>
  <div class="main">
    <!-- 动画组件 -->
    <button @click="flag2 = !flag2">切换动画</button>
    <transition name="fade">
      <div v-if="flag2" class="box">我是动画啊</div>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
let flag2 = ref<Boolean>(true)
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;
  .box {
    width: 100px;
    height: 100px;
    background: red;
  }
  // 进入前
  .fade-enter-from {
    width: 0;
    height: 0;
    opacity: 0;
  }
  // 进入的这个阶段
  .fade-enter-active {
    transition: all 2s ease;
  }
  // 进入后
  .fade-enter-to {
    width: 100px;
    height: 100px;
    opacity: 1;
  }
  // 离开前
  .fade-leave-from {
    width: 100px;
    height: 100px;
    opacity: 1;
  }
  // 进入的这个阶段
  .fade-leave-active {
    transition: all 2s ease;
  }
  // 离开后
  .fade-leave-to {
    width: 0;
    height: 0;
    opacity: 0;
  }
}
</style>
  • 效果
    在这里插入图片描述

自定义过度 动画的类名

  • enter-from-class、enter-active-class、enter-to-class、leave-from-class、leave-active-class、leave-to-class
  • 以上这6个类名 可以重新自定义类名
  • 实现的效果 入简单的fade一致
<template>
  <div class="main">
    <!-- 动画组件 -->
    <button @click="flag2 = !flag2">切换动画</button>
    <!-- name="fade" -->
    <transition enter-from-class="e-from" enter-active-class="e-active" enter-to-class="e-to" leave-from-class="l-from" leave-active-class="l-active" leave-to-class="l-to">
      <div v-if="flag2" class="box">我是动画啊</div>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
let flag2 = ref<Boolean>(true)
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;
  .box {
    width: 100px;
    height: 100px;
    background: red;
  }
  // 进入前
  .e-from {
    width: 0;
    height: 0;
    opacity: 0;
  }
  // 进入的这个阶段
  .e-active {
    transition: all 2s ease;
  }
  // 进入后
  .e-to {
    width: 100px;
    height: 100px;
    opacity: 1;
  }
  // 离开前
  .l-from {
    width: 100px;
    height: 100px;
    opacity: 1;
  }
  // 进入的这个阶段
  .l-active {
    transition: all 2s ease;
  }
  // 离开后
  .l-to {
    width: 0;
    height: 0;
    opacity: 0;
  }
}
</style>

transition的生命周期

  • @before-enter => 就是动画 进入之前触发
  • @enter => 就是动画 在运行过程中的曲线等
  • @after-enter => 就是动画 执行完毕触发
  • @enter-cancelled => 动画被效果打断
  • @before-leave => 动画离开前触发
  • @leave=“leave” => 就是动画 在离开时,运行过程中的曲线等
  • @after-leave => 动画离开完毕触发
  • @leave-cancelled => 动画被效果打断
<template>
  <div class="main">
    <!-- 动画组件 :duration="1000" 动画执行时间 1s-->
    <button @click="flag2 = !flag2">切换动画</button>
    <transition @before-enter="EnterFrom">
      <div v-if="flag2" class="box">我是动画啊</div>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import 'animate.css'
const EnterFrom = (el: Element) => {
  console.log('EnterFrom', el) // el 当前 transition 包裹的标签
}

let flag2 = ref<Boolean>(true)
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;

  .box {
    width: 100px;
    height: 100px;
    background: red;
  }
}
</style>

配合 gsap 的使用

  • 下载:yarn add gsap -S
  • 官网:gsap
借组gsap 实现一个很丝滑的 动画
  • 效果:就是从最开始的宽高100,丝滑得缩小为0,然后显示的时候,从0到100
<template>
  <div class="main">
    <!-- 动画组件 :duration="1000" 动画执行时间 1s-->
    <button @click="flag2 = !flag2">切换动画</button>
    <transition @before-enter="EnterFrom" @enter="EnterActive" @leave="leaveActive">
      <div v-if="flag2" class="box">我是动画啊</div>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import 'animate.css'
import gsap from 'gsap'
const EnterFrom = (el: Element) => {
  // console.log('EnterFrom', el) // el 当前 transition 包裹的标签
  gsap.set(el, {
    width: 0,
    height: 0,
    opacity: 0,
  })
}
const EnterActive = (el: Element, done: gsap.Callback) => {
  gsap.to(el, {
    width: 100,
    height: 100,
    onComplete: done,
    opacity: 1,
  })
}
const leaveActive = (el: Element, done: gsap.Callback) => {
  gsap.to(el, {
    width: 0,
    height: 0,
    opacity: 0,
    onComplete: done,
  })
}

let flag2 = ref<Boolean>(true)
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;

  .box {
    width: 100px;
    height: 100px;
    background: red;
  }
}
</style>

transition 结合 animate动画库

animate官网

  • 下载使用
    • yarn add animate.css -S

一个简单的

  • 离开时从右侧划来,进入时从左侧划出
<template>
  <div class="main">
    <!-- 动画组件 -->
    <button @click="flag2 = !flag2">切换动画</button>
    <transition enter-active-class="animate__animated animate__fadeInLeft" leave-active-class="animate__animated animate__fadeInRight">
      <div v-if="flag2" class="box">我是动画啊</div>
    </transition>
  </div>
</template>

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

let flag2 = ref<Boolean>(true)
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;

  .box {
    width: 100px;
    height: 100px;
    background: red;
  }
}
</style>

transition结合 gsap动画库

<template>
  <div class="main">
    <!-- 动画组件 :duration="1000" 动画执行时间 1s-->
    <button @click="flag2 = !flag2">切换动画</button>
    <transition @before-enter="EnterFrom" @enter="EnterActive" @leave="leaveActive">
      <div v-if="flag2" class="box">我是动画啊</div>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import 'animate.css'
import gsap from 'gsap'
const EnterFrom = (el: Element) => {
  // console.log('EnterFrom', el) // el 当前 transition 包裹的标签
  gsap.set(el, {
    width: 0,
    height: 0,
    opacity: 0,
  })
}
const EnterActive = (el: Element, done: gsap.Callback) => {
  gsap.to(el, {
    width: 100,
    height: 100,
    onComplete: done,
    opacity: 1,
  })
}
const leaveActive = (el: Element, done: gsap.Callback) => {
  gsap.to(el, {
    width: 0,
    height: 0,
    opacity: 0,
    onComplete: done,
  })
}

let flag2 = ref<Boolean>(true)
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;

  .box {
    width: 100px;
    height: 100px;
    background: red;
  }
}
</style>

transition-group过度列表

  • 就是对一个列表的操作时,
    • 若是新增一个数组数据,也就是数组新增就是触发进入动画(从左侧 移到最末尾的位置,新增了一个数据)
    • 删除数组时,也就是触发离开动画(从当前最末尾位置,慢慢移除,并且删除掉改数据)
<template>
  <div class="main">
    <button @click="add">新增</button>
    <button @click="del">删除</button>
    <div class="wraps">
      <!-- <transition-group tag="section">  section 就是可以帮你多套一层 标签 -->
      <transition-group enter-active-class="animate__animated animate__backInLeft" leave-active-class="animate__animated animate__backInRight">
        <div class="item" v-for="item in list" :key="item">{{ item }}</div>
      </transition-group>
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue'
import 'animate.css'

let flag2 = ref<Boolean>(true)
let list = reactive<number[]>([1, 2, 3, 4])
const add = () => {
  list.push(list.length + 1)
}
const del = () => {
  list.pop()
}
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;
  .wraps {
    display: flex;
    flex-wrap: wrap;
    word-break: break-all;
    border: 1px solid #ccc;
    .item {
      margin-right: 10px;
      font-size: 40px;
    }
  }
}
</style>

transition-group 结合 lodash 实现一个九方格 随机数

  • 实现一个81宫格的 随机数切换动画
  • lodash官网
  • 下载:
    • yarn add lodash -S
    • yarn add @types/lodash -D
<template>
  <div class="main">
    <button @click="random">随机数</button>
    <!-- move-class="random" 过度的类名 -->
    <transition-group move-class="random" class="wraps" tag="div">
      <div class="item" v-for="item in list" :key="item.id">{{ item.num }}</div>
    </transition-group>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue'
import 'animate.css'
import lodash from 'lodash'

let flag2 = ref<Boolean>(true)
let list = ref<number[]>(
  Array.apply(null, { length: 81 } as number[]).map((_, index) => {
    return {
      id: index,
      num: (index % 9) + 1,
    }
  })
)
// console.log('lodash', lodash.add(0.2, 0.3)) // 计算和数

const random = () => {
  list.value = lodash.shuffle(list.value)
}
</script>
<style lang="scss" scoped>
.main {
  flex: 1;
  margin: 14px;
  border: 1px solid #ccc;
  overflow: auto;
  .random {
    transition: all 1s;
  }
  .wraps {
    display: flex;
    flex-wrap: wrap;
    word-break: break-all;
    width: calc(30px * 10);
    .item {
      border: 1px solid #333;
      font-size: 20px;
      width: 30px;
      height: 30px;
      text-align: center;
    }
  }
}
</style>

数字状态的过度

  • 数字状态的过度,比如说就是一个input框之中输入了一个值为10,那么监听这个input输入的值发生变化时候,触发另外一个状态过度的数据
  • num
    • curNum 输入框监听的值
    • tweenedNumber 状态过度的值,数字的抖动值
<template>
  <div class="main">
    <input type="number" v-model="num.curNum" />
    数字的过度效果 {{ parseInt(num.tweenedNumber).toFixed(0) }}
  </div>
</template>

<script setup lang="ts">
import { reactive, watch } from 'vue'
import gsap from 'gsap'
type num = {
  curNum: String
  tweenedNumber: String
}

const num = reactive<num>({
  curNum: '',
  tweenedNumber: '',
})
watch(
  () => num.curNum,
  (newV) => {
    console.log('newV', newV)
    gsap.to(num, {
      duration: 1,
      tweenedNumber: newV,
    })
  }
)
</script>
Logo

前往低代码交流专区

更多推荐