首页 > 编程笔记

Vue transtion实现过渡动画效果(非常详细)

Vue 在插入、更新或者移除 DOM 时,提供了多种不同方式的应用过渡效果,包括:
为什么网页需要添加过渡和动画效果呢?因为过渡和动画效果能够提高用户的体验,帮助用户更好地理解页面中的功能。

本节重点学习用 transition 组件实现过渡和动画效果。

transition组件

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡:

1) CSS过渡

常用的过渡都是使用 CSS 过渡。下面是一个没有使用过渡效果的示例,通过一个按钮控制 p 元素显示和隐藏。
<div id="app">
    <button v-on:click="show = !show">
        上京即事五首·其一
    </button>
    <p v-if="!show">大野连山沙作堆,白沙平处见楼台。</p>
    <p v-if="!show">行人禁地避芳草,尽向曲阑斜路来。</p>
</div>
<!--引入Vue文件-->
<script src="https://unpkg.com/vue@next"></script>
<script>
    //创建一个应用程序实例
    const vm= Vue.createApp({
        //该函数返回数据对象
        data(){
          return{
             show:true
           }
        }
    //在指定的DOM元素上装载应用程序实例的根组件
    }).mount('#app');
</script>
在 Chrome 浏览器中运行程序,单击按钮后的效果如下图所示。


图 1 没有过渡效果

当单击按钮时,会发现 p 标签出现或者消失,但没有过渡效果,用户体验不太好。可以使用 Vue 的 transition 组件来实现消失或者隐藏的过渡效果。使用 Vue 过渡的时候,首先把过渡的元素添加到 transition 组件中。其中 .v-enter、.v-leave-to、.v-enter-active 和 .v-leave-active 样式是定义动画的过渡样式。

【实例】添加 CSS 过渡效果。
<style>
   /*v-enter-active入场动画的时间段*/
   /*v-leave-active离场动画的时间段*/
   .v-enter-active, .v-leave-active{
       transition: all .5s ease;
   }
   /*v-enter是一个时间点,是进入之前元素的起始状态,此时还没有进入*/
   /*v-leave-to是一个时间点,是动画离开之后,离开的终止状态,此时元素动画已经结束*/
   .v-enter, .v-leave-to{
       opacity: 0.2;
       transform:translateY(200px);
   }
</style>
<div id="app">
   <button v-on:click="show = !show">
       古诗欣赏
   </button>
   <transition>
       <p v-if="!show">鸿雁长飞光不度,鱼龙潜跃水成文。</p>
   </transition>
</div>
<!--引入Vue文件-->
<script src="https://unpkg.com/vue@next"></script>
<script>
   //创建一个应用程序实例
   const vm= Vue.createApp({
       //该函数返回数据对象
       data(){
         return{
            show:true
          }
       }
   //在指定的DOM元素上装载应用程序实例的根组件
   }).mount('#app');
</script>
在 Chrome 浏览器中运行程序,单击“古诗欣赏”按钮,可以发现,p 元素刚开始在下侧 200px 的位置开始,透明度为 0.2,如下图所示:


图 2 过渡效果

然后过渡到初始的位置,如下图所示。


图 3 显示内容

2) 过渡的类名

在进入/离开的过渡中,会有 6 个 class 切换:
一个过渡效果包括两个阶段:一个是进入动画(Enter);另一个是离开动画(Leave)。

进入动画包括 v-enter、v-enter-to 两个时间点和 v-enter-active 一个时间段。离开动画包括 v-leave、v-leave-to 两个时间点和 v-leave-active 一个时间段。具体如下图所示:


图 4 过渡动画的时间点

定义过渡时,首先使用 transition 元素把需要被过度控制的元素包裹起来,然后自定义两组样式来控制 transition 内部的元素实现过渡。对于这些在过渡中切换的类名来说,如果使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。

前面示例中定义的样式,在所有动画中会公用,transition 有一个 name 属性,可以通过它来修改过渡样式的名称。如果使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter。这样做的好处是区分每个不同的过渡和动画。

下面通过一个按钮来触发两个过渡效果,一个从右侧 150px 的位置开始,一个从下面 200px 的位置开始。

【实例】多个过渡效果。
<style>
   .v-enter-active, .v-leave-active {
       transition: all 0.5s ease;
   }
   .v-enter, .v-leave-to{
       opacity: 0.2;
       transform:translateX(150px);
   }
   .my-transition-enter-active, .my-transition-leave-active {
       transition: all 0.8s ease;
   }
   .my-transition-enter, .my-transition-leave-to{
       opacity: 0.2;
       transform:translateY(200px);
   }
   </style>
<div id="app">
   <button v-on:click="show = !show">
       出郊
   </button>
   <transition>
       <p v-if="!show">高田如楼梯,平田如棋局。</p>
   </transition>
   <transition name="my-transition">
       <p v-if="!show">白鹭忽飞来,点破秧针绿。</p>
</transition>
</div>
  
<!--引入Vue文件-->
<script src="https://unpkg.com/vue@next"></script>
<script>
   //创建一个应用程序实例
   const vm= Vue.createApp({
       //该函数返回数据对象
       data(){
         return{
            show:true
          }
       }
   //在指定的DOM元素上装载应用程序实例的根组件
   }).mount('#app');
</script>
在 Chrome 浏览器中运行程序,单击“出郊”按钮,触发两个过渡效果,如下图所示:


图 5 多个过渡效果图

最终状态如下图所示:


图 6 最终状态

3) CSS动画

CSS 动画的用法与 CSS 过渡差不多,区别是在动画中,v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。

CSS动画的用法如下。
<style>
    /*进入动画阶段*/
    .my-enter-active {
        animation: my-in .5s;
    }
    /*离开动画阶段*/
    .my-leave-active {
        animation: my-in .5s reverse;
    }
    /*定义动画my-in*/
    @keyframes my-in {
        0% {
            transform: scale(0);
        }
        50% {
            transform: scale(1.5);
        }
        100% {
            transform: scale(1);
        }
    }
</style>
<div id="app">
    <button @click="show = !show">对雪</button>
    <transition name="my">
        <p v-if="show">六出飞花入户时,坐看青竹变琼枝。如今好上高楼望,盖尽人间恶路岐。</p>
    </transition>
</div>
<!--引入Vue文件-->
<script src="https://unpkg.com/vue@next"></script>
<script>
    //创建一个应用程序实例
    const vm= Vue.createApp({
        //该函数返回数据对象
        data(){
          return{
             show:true
           }
        }
    //在指定的DOM元素上装载应用程序实例的根组件
    }).mount('#app');
</script>
在 Chrome 浏览器中运行程序,单击“对雪”按钮时,触发 CSS 动画,效果如下图所示:


图 7 CSS动画效果

4) 自定义过渡的类名

可以通过以下 attribute 来自定义过渡的类名:
它们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库(如 Animate.css)的结合使用十分有用。

下面的示例在 transition 组件中使用 enter-active-class 和 leave-active-class 类,结合 animate.css 动画库实现动画效果。

【实例】自定义过渡的类名。
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet"
type="text/css">
<div id="app">
    <button @click="show = !show">
        早春
    </button>
<!--enter-active-class:控制动画的进入-->
<!--leave-active-class:控制动画的离开-->
<!--animated 类似于全局变量,它定义了动画的持续时间-->
<!--bounceInUp和slideInRight是动画具体的动画效果的名称,可以选择任意的效果-->
    <transition
            enter-active-class="animated bounceInUp"
            leave-active-class="animated slideInRight"
    >
        <p v-if="show">春销不得处,唯有鬓边霜。</p>
    </transition>
</div>
<!--引入Vue文件-->
<script src="https://unpkg.com/vue@next"></script>
<script>
    //创建一个应用程序实例
    const vm= Vue.createApp({
        //该函数返回数据对象
        data(){
          return{
             show:true
           }
        }
        //在指定的DOM元素上装载应用程序实例的根组件
     }).mount('#app');
</script>
在浏览器运行,单击“早春”按钮,触发进入动画,效果如下图所示:


图 8 进入动画效果

再次单击“早春”按钮,触发离开动画,效果如图 9 所示。


图 9 离开动画效果

5) 动画的JavaScript钩子函数

可以在 <transition> 组件中声明 JavaScript 钩子,它以属性的形式存在。例如下面的代码:
<transition
       进入动画钩子函数
:before-enter表示动画入场之前,此时动画还未开始,可以在其中设置元素开始动画之前的起始样式
       v-on:before-enter="beforeEnter"
:enter表示动画,开始之后的样式,可以设置完成动画的结束状态
       v-on:enter="enter"
:after-enter表示动画完成之后的状态
       v-on:after-enter="afterEnter"
:enter-cancelled用于取消开始动画的
       v-on:enter-cancelled="enterCancelled"
       离开动画钩子函数,离开动画和进入动画钩子函数说明类似
       v-on:before-leave="beforeLeave"
       v-on:leave="leave"
       v-on:after-leave="afterLeave"
       v-on:leave-cancelled="leaveCancelled"
>
   <!-- ... -->
</transition>
然后在 Vue 实例的 methods 选项中定义钩子函数的方法:
<script>
   //创建一个应用程序实例
   const vm= Vue.createApp({
       //该函数返回数据对象
       data(){
         return{
            show:true
          }
       },
       methods: {
           // 进入中
           beforeEnter: function (el) {
               ...
           },
           // 当与 CSS 结合使用时
           // 回调函数 done 是可选的
           enter: function (el, done) {
               ...
               done()
           },
           afterEnter: function (el) {
               ...
           },
           enterCancelled: function (el) {
               ...
           },
           // 离开时
           beforeLeave: function (el) {
               ...
           },
           // 当与 CSS 结合使用时
           // 回调函数 done 是可选的
           leave: function (el, done) {
               ...
               done()
           },
           afterLeave: function (el) {
               ...
           },
           // leaveCancelled 只用于 v-show 中
           leaveCancelled: function (el) {
               ...
           }
   //在指定的DOM元素上装载应用程序实例的根组件
   }).mount('#app');
</script>
这些钩子函数可以结合 CSS transitions/animations 使用,也可以单独使用。

当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。对于仅使用 JavaScript 过渡的元素,推荐添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。

下面使用 velocity.js 动画库结合动画钩子函数来实现一个简单示例。
<!--Velocity和jQuery.animate 的工作方式类似,也是用来实现JavaScript动画的一个很棒的选择
-->
<script src="velocity.js"></script>
<div id="app">
   <button @click="show = !show">
       雪晴晚望
   </button>
   <transition
           v-on:before-enter="beforeEnter"
           v-on:enter="enter"
           v-on:leave="leave"
           v-bind:css="false"
   >
       <p v-if="show">
           野火烧冈草,断烟生石松。
       </p>
   </transition>
</div>
<!--引入Vue文件-->
<script src="https://unpkg.com/vue@next"></script>
<script>
   //创建一个应用程序实例
   const vm= Vue.createApp({
       //该函数返回数据对象
       data(){
         return{
            show:false
          }
       },
       methods: {
           // 进入动画之前的样式
           beforeEnter: function (el) {
            // 注意:动画钩子函数的第一个参数:el,表示要执行动画的那个DOM元素,
            // 是一个原生的JS DOM对象
            // 可以认为,el是通过document.getElementById('')方式获取到原生JS DOM对象的
               el.style.opacity = 0;
               el.style.transformOrigin = 'left';
           },
           // 进入时的动画
           enter: function (el, done) {
               Velocity(el, { opacity: 1, fontSize: '2em' }, { duration: 300 });
               Velocity(el, { fontSize: '1em' }, { complete: done });
           },
           //离开时的动画
           leave: function (el, done) {
               Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration:
600 });
               Velocity(el, { rotateZ: '100deg' }, { loop: 5 });
               Velocity(el, {
                   rotateZ: '45deg',
                   translateY: '30px',
                   translateX: '30px',
                   opacity: 0
               }, { complete: done })
           }
       }
   //在指定的DOM元素上装载应用程序实例的根组件
   }).mount('#app');
</script>
在 Chrome 浏览器中运行程序,单击“雪晴晚望”按钮,进入动画,效果如下图所示:


图 10 进入动画效果

再次单击“雪晴晚望”按钮,离开动画,效果如下图所示。


图 11 离开动画效果

Velocity 动画的配置选项如下:
duration:400,                //动画执行时间
easing: "swing",             //缓动效果
queue: "",                   //队列
begin:undefined,             //动画开始时的回调函数
progress: undefined,         //动画执行中的回调函数(该函数会随着动画的执行不断被触发)
complete: undefined,         //动画结束时的回调函数
display: undefined,          //动画结束时设置元素的css display属性
visibility: undefined,       //动画结束时设置元素的css visibility属性
loop: false,                 //循环次数
delay: false,                //延迟
mobileHA: true               //移动端硬件加速(默认开启)

推荐阅读