自学内容网 自学内容网

Vue中使用<Transition>与<TransitionGroup>

目录

介绍

CSS过渡类

为过渡效果命名

CSS的transition

CSS的transform

性能考量

出现时过渡

元素间过渡

过渡模式

使用Key属性过渡

和的区别

进入/离开动画

移动动画

一个购物车飞跃例子

介绍

传统HTML中,我们可以使用CSS属性:“animation”与“transform”进行动画处理,而Vue为我们提供了两种内置组件:“<Transition>”与“<TransitionGroup>

  • Vue文件中可以直接使用<Transition><TransitionGroup>
  • 使用Vue为静态页面增强时,请使用“<transition-group>

CSS过渡类

Vue为我们提供了六种CSS动画类,方便我们进行操作:

  • v-enter-from:进入动画的起始状态(在元素插入之前添加,元素插入完成后下一帧被移除)
  • v-enter-active:进入动画的生效状态(应用于整个动画阶段),在元素插入之前添加,在过渡或动画完成之后移除(该clss可以用来定义动画的持续时间、延迟与速度曲线类型)
  • v-enter-to:进入动画的结束状态。在元素插入完成后的下一帧被添加(v-enter-from被移除的同时),在过渡动画完成之后移除
  • v-leave-from:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除
  • v-leave-active:离开动画的生效状态(应用于整个动画阶段),在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除(该clss可以用来定义动画的持续时间、延迟与速度曲线类型)
  • v-leave-to:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加(也就是v-leave-from被移除的同时),在过渡或动画完成之后移除

尽管如此,关于上述概念,同学们可能还会有所疑惑,因为官方文档给出的概念过于繁琐,因此在这里给出作者的一种“大白话”理解:

  • v-enter-from动画起始状态:“哪个位置”、“自身属性(背景颜色、透明度等)”开始动画
  • v-enter-active动画执行过程:“动画以什么方式执行?(ease、ease-in、ease-in-out)等”、“动画执行多久(duration)”、“元素的哪一部分执行动画(全部、局部)”
  • v-enter-to动画结束状态:“动画最终会在哪里?”、“动画属性最终是什么样子?”

v-leave与上述v-enter一致,不再赘述

<Transition>

  • <Transition>会在一个元素或组件进入离开DOM时应用动画

<Transition>触发条件如下:

  1. 由“v-if”所触发的切换
  2. 由“v-show”所触发的切换
  3. 由特殊元素<component>切换的动态组件
  4. 改变特殊的key属性

为过渡效果命名

我们可以给<Transition>组件穿一个“name”属性来声明一个过渡效果

<Transition name="fade">
    <p v-show="flag">Hello World!</p>
</Transition>
  •  对于一个有名字的过渡效果,对它起作用的过渡class会以其名字而不是v作为前缀
  • 例如上方例子被应用的class将会是“fade-enter-active”而不是“v-enter-active
.fade-enter-active,.fade-leave-active {
  transition:opacity 0.5s ease;
}
.fade-enter-from,.fade-leave-to {
  opacity: 0;
}

效果:

CSS的transition

<Transition>一般都会搭配原生CSS过渡一起使用

.fade-enter-active {
  transition:all 0.5s ease-out;
}
.fade-leave-active {
  transition:all 0.8s cubic-bezier(1,0.5,0.8,1)
}
.fade-enter-from,.fade-leave-to {
  transform: translateX(20px);
  opacity: 0;
}

效果:

CSS的transform

原生CSS动画CSS transition的应用方式基本上是相同的,只有一点不同,那就是“*-enter-from”不是在元素插入后立即移除,而是在一个“animationend”事件触发时被移除

<template>
  <div style="position:absolute;margin: 0px 200px;">
    <Transition name="fade">
      <p v-show="flag">Hello World!</p>
    </Transition>
    <button @click="flag = !flag">出现/消失</button>
  </div>
</template>

<style scpoed>
.fade-enter-active {
  animation: bounce-in 0.5s;
}
.fade-leave-active {
  animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.25);
  }
  100% {
    transform: scale(1);
  }
}
</style>

效果:

性能考量

制作动画应尽量使用“transform”和“opacity”等,而不应使用“height”、“margin”这些属性,因为:

  1. 它们在动画过程中不会影响到DOM结构,不会每一帧都触发CSS布局重新计算
  2. 大多数现代浏览器执行transform动画时可以利用GPU进行硬件加速

出现时过渡

如果想在某个节点初次渲染时应用一个过渡效果(页面加载时),可以添加“appear”属性实现

<Transition appear>
  ...
</Transition>

元素间过渡

除了通过“v-if”和“v-show”切换一个元素,我们还可以通过“v-if”、“v-else-if”、“v-else”进行几个组件之间切换,只要确保任一时刻只会有一个元素被渲染即可

<template>
  <div style="position:absolute;margin: 0px 200px;">
    <Transition name="fade" mode="out-in">
      <p v-if="flag == 'Tom'">I am Tom</p>
      <p v-else-if="flag == 'Amy'">I am Amy</p>
      <p v-else="flag == 'Sam'">I am Sam</p>
    </Transition>
  </div>
  <button @click="flag = 'Tom'">Tom</button>
  <button @click="flag = 'Amy'">Amy</button>
  <button @click="flag = 'Sam'">Sam</button>
</template>
<style scpoed>
.fade-enter-from {
  transform: translateY(10px);
  opacity: 0;
}
.fade-leave-to{
  transform: translateY(-10px);
  opacity: 0;
}
.fade-enter-active,.fade-leave-active {
  transition: transform 0.5s, opacity 0.5s;
}
.fade-enter-to,.fade-leave-from {
  transform: translateY(0);
  opacity: 1;
}
</style>

效果:

  • 可以发现,上一个元素的离开动画和下一个元素的进入动画是同时发生的,这样会有很大的顿挫感,不过好在Vue提供“过渡模式”帮助我们解决这个问题

过渡模式

当我们想要先执行离开动画,然后在其完成之后再执行元素的进入动画。手动编排这样的动画是非常复杂的,不过我们可以通过向“<Transition>”传入一个“mode”属性来实现这个行为:

<Transition mode="out-in">
  ...
</Transition>

效果:

使用Key属性过渡

有时为了触发过渡,我们需要强制重新渲染DOM元素

我们可以使用key属性“强标记”一个元素

不使用key属性:

<script setup>
import {ref} from 'vue'
const count = ref(0)
setInterval(() => count.value += 1,1000)
</script>

<template>
  <div style="position:absolute;margin: 0px 200px;">
    <Transition name="fade" mode="out-in">
      <p>{{count}}</p>
    </Transition>
  </div>
</template>
<style scpoed>
.fade-enter-from {
  transform: translateY(10px);
  opacity: 0;
}
.fade-leave-to{
  transform: translateY(-10px);
  opacity: 0;
}
.fade-enter-active,.fade-leave-active {
  transition: transform 0.5s, opacity 0.5s;
}
.fade-enter-to,.fade-leave-from {
  transform: translateY(0);
  opacity: 1;
}
</style>

效果:

使用key属性:

<p :key="count">{{count}}</p>

效果:

可以发现,如果不使用“key”属性,只有文本节点会被更新,因此不会触发过渡

但是有了“key”属性,Vue就知道在count改变时新建一个<p>元素,因此<Transition>组件有两个不同的元素在它们之间进行过渡

<TransitionGroup>

<TransitionGroup>用于对“v-for”列表中的元素或组件的插入、移除和顺序改变添加动画效果

<TransitionGroup>和<Transition>的区别

<TransitionGroup>支持和<Transition>基本相同的属性CSS过渡classJavaScript钩子监听器,但有以下几点区别:

  1. 默认情况下,它不会渲染一个容器元素,但是你可以通过传入一个“tag”属性来指定一个元素作为容器元素来渲染
  2. 过渡模式”在这里不可用,因为我们不再是在互斥的元素之间进行切换
  3. 列表中的每个元素都必须有一个独一无二的key属性
  4. CSS过渡class会被应用在列表内的元素上,而不是容器元素上

进入/离开动画

一个<TransitionGroup>对一个“v-for”列表添加进入/离开动画的示例:

<script setup>
import {ref} from 'vue'
const items = ref([1,2,3,4,5])
const addValue = ref(6)
function addToRandomPosition() {  
    const randomIndex = Math.floor(Math.random() * (items.value.length + 1)); 
    items.value.splice(randomIndex, 0,addValue.value);
    addValue.value += 1;
} 
function removeRandomElement(arr) {  
    if (arr.length === 0) {  
        return null;
    }  
    const randomIndex = Math.floor(Math.random() * items.value.length);  
    items.value.splice(randomIndex, 1);  
}  
</script>

<template>
  <div style="position:absolute;margin: 0px 200px;">
    <TransitionGroup name="fade" tag="ul">
      <li v-for="item in items" :key="item">
        {{ item }}
      </li>
    </TransitionGroup>
    <button @click="addToRandomPosition">随机添加一项</button>
    <button @click="removeRandomElement">随机删除一项</button>
  </div>
</template>
<style scpoed>
.fade-enter-from {
  transform: translateX(10px);
  opacity: 0;
}
.fade-leave-to{
  transform: translateY(-10px);
  opacity: 0;
}
.fade-enter-active,.fade-leave-active {
  transition: transform 0.5s, opacity 0.5s;
}
</style>

效果:

移动动画

上面的例子中有一些明显的缺陷:当某一项插入移除时,它周围的元素会立即发生“跳跃”而不是平稳地移动(具体表现为:“坍塌式的插入、移除”,观感不好)

解决办法是,给“enter-activeleave-active添加一个v-move(对移动中的元素应用的过渡)”

给“leave-active添加一个absolute属性,让它脱离布局流,以便可以正确地计算移动的动画

.fade-move, /* 对移动中的元素应用的过渡 */
.fade-enter-active,
.fade-leave-active {
  transition: all 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

/* 确保将离开的元素从布局流中删除
  以便能够正确地计算移动的动画。 */
.fade-leave-active {
  position: absolute;
}

效果:

一个购物车飞跃例子

在电商等很多平台中,会有如下场景:

点击某商品添加按钮,该商品会飞跃到购物车,并消失

现在,我们尝试使用Vue简单模拟

思路如下:“点击按钮后,元素进行X和Y方向的移动,且逐渐缩小并消失

<script setup>
import {ref} from 'vue'
const showAnimation = ref(false)
function startMove() {
  showAnimation.value = true
  //定时器用来隐藏小球,时间为小球动画时间
  setTimeout(() => {
    showAnimation.value = false
  },1000)
}
</script>

<template>
  <div style="position:absolute;margin: 200px 200px;">
    <div style="border: 1px solid;height: 60px;width: 60px;">
      <Transition name="fade">
        <div class="small-ball"  v-show="showAnimation"></div>
      </Transition>
    </div>
  </div>
  <button @click="startMove" style="position:absolute;top:200px;left:100px;">开始移动</button>
</template>
<style scpoed>
.small-ball {
  width:60px;
  height: 60px;
  background-color: red;
  border-radius: 50%;
}
/* 初始时小球应该先显示出来因此opacity为1 */
.fade-enter-from {
  opacity: 1;
}
.fade-enter-active {
  transition: all 1s ease;
}
/* 小球进入动画的位置和小球离开动画的开始位置应该一致 */
/* 因为小球是先从隐藏变为显示,再从显示变为隐藏 */
.fade-enter-to,.fade-leave-from {
  transform: translate(100px,100px) scale(0);
  opacity: 0;
}
</style>

效果:


原文地址:https://blog.csdn.net/zheshiyangyang/article/details/144112846

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!