Vue中过渡和动画

在Vue中使用动画时,经常是一知半解,有时候加上动画不知道为什么不执行,有时候设置的动画与我们想象中不太一样。因此,通过本篇文章对Vue中的动画做了一次详细的学习,本文内容全部来自Vue官方文档。

概述

  1. 过渡/动画的适用条件

我们想要使用过渡和动画,首先需要了解什么情况下能够使用动画,Vue在插入、更新或者删除DOM时,提供了多种不同方式的过渡效果,通常是使用v-if、v-show和动态组件的情况下。也就是说我们只有在这几种情况下设置过渡动画才有效果,这就是为什么我们有时候设置过渡动画无效的原因之一。

  1. 有哪些常见的过渡/动画实现方式 vue Vue中过渡/动画主要包括单元素/组件的过渡,多元素/组件的过渡和列表的过渡。每种过渡都有对应的实现方式,接下来我们一一介绍这些实现。

单元素/组件的过渡和动画

1. css transition

Vue提供了transition的封装组件,具体使用方法如下:

  1. 给需要设置过渡的元素作为transition的子元素
  2. transition 加上name属性,会自动应用6个class。通过这些class的切换,实现过渡效果。
  3. 想要实现过渡效果,必须合理地设置class的值。其中过渡必须有初始值,然后对应的css中有新的值。
.show-enter-active, .show-leave-active {
  transition: all 3s;
}
.show-enter, .show-leave-to  {
  opacity: 0;
  width:300px;  // 新的值
}
p{
  border:1px solid red;
  width:100px;  // 初始值
}

6个class

transition在应用过渡的过程中通过class的切换来实现过渡效果,其中主要包括: 进入过渡:v-enter,v-enter-activev-enter-to3个class。 离开过渡:v-leave,v-leave-activev-leave-to3个class。 在元素从隐藏到显示会触发进入过渡的3个class的切换,但是不会触发离开过渡的3个class的切换。 在元素从显示到隐藏会触发离开过渡的3个class的切换,但是不会触发进入过渡的3个class的切换。
v-enter:实际上就是动画的第一帧。

p{
  border:1px solid red;
  width:100px;
  background:black;
}
.show-enter{
  background:red;
}

这里show-enter表示进入动画的第一帧元素背景是红色。
v-enter-active:表示进入动画的过程,用来描述动画的执行,比如执行多少秒,哪些属性执行,类似于CSS3中的transition。这是每个动画都必须有的

.show-enter-active{
  transition: all 3s;
}

表示所有的属性进入动画后执行3s。
v-enter-to:定义进入动画过渡的结束状态,也就是进入动画的最后一帧。通常是变成元素正常展示的状态。

.show-enter-to{
  background:black;
}

一般是不需要设置v-enter-to。一般v-enter-to就是元素默认的样式。

这三个类的添加和移除顺序为
第一帧:添加v-enterv-enter-active两个class
第二帧:v-enter被移除,添加v-enter-to这个class。这时候有v-enter-activev-enter-to两个class。
最后动画过渡结束,移除v-enterv-enter-to类。

注意这几个class只有在元素插入时才有,也就是在DOM结构中插入一个新的元素时才有(比如v-if = true的时候)。如果是从DOM结构中删除元素并不会有这三个class。也就是说我们要理解过渡的执行,并不是所有的动画都需要6个class,如果你只是想在 显示元素时假如过渡,那么你只需要设置v-enter,v-enter-activev-enter-to就可以了。

v-leave:动画离开时的第一帧,一般不需要设置,默认为当前的样式。
v-leave-active::定义离开过渡动画的过程,用来描述动画的离开过程。通常也是用来设置过渡时间,延迟和曲线函数等。

.show-leave-active {
  transition: all 10s;
}

v-leave-to:定义动画结束时的样式。也是过渡的最后一帧的状态。
总结:6个class,通常只需要设置4个。v-enterv-enter-active(其中v-enter-to是元素展示时的默认样式)。v-leave-activev-leave-to(其中v-leave是元素隐藏时的默认样式)。而且,通常进入动画和离开动画的过程一致,因此,最终的设置通常如下:

.show-enter-active, .show-leave-active {
  transition: opacity .5s;
}
.show-enter, .show-leave-to{
  opacity: 0;
}

2. css animation

vue中animation动画的实现跟CSS3差不多。只不过这里是通过v-enter-activev-leave-active来实现。 我们只需要确保两件事:

  1. 定义v-enter-activev-leave-active这两个class。不同于transition,我们不需要定义v-enter和v-leave-to这两个class。
  2. 定义一个@keyframes动画。
  3. 确保正常动画100%时元素处于正常状态(特殊设计的动画效果除外)。
.bounce-enter-active {
  animation: bounce-in .5s;
}
.bounce-leave-active {
  animation: bounce-in .5s reverse;
}
/* 通过定义一个动画。然后直接设置动画的过程就可以了。 */
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    /* 通常要确保最后结束的状态是正常状态 */
    transform: scale(1);
  }
}

3. 使用自定义过渡类名配合第三方库来做过渡/动画

通常情况下,我们自己写的过渡效果可能不太酷炫,这时候我们希望能够引入一些第三方库的动画效果。Vue提供了以下自定义类名来配合第三方库实现动画。

  • enter-class
  • enter-active-class
  • enter-to-class
  • leave-class
  • leave-active-class
  • leave-to-class 他们的优先级高于普通的类名。我们可以使用第三方库animate.css中的类名来作为transition中的自定义类名,从而借助一些第三方库实现一些酷炫的动画效果。
<div id="example-3">
  <button @click="show = !show">
    Toggle render
  </button>
  <transition
    enter-active-class="animated shake"
    leave-active-class="animated bounceOutRight"
  >
    <p v-if="show">hello</p>
  </transition>
</div>

上面的代码中,我们通过设置enter-active-class的类名为animated shake从而调用了animate.css中的shake类实现的过渡效果。

4. Javascript钩子实现过渡/动画

一些情况下,我们希望通过js来实现过渡/动画,而不是仅仅通过css来实现。Vue提供了一些钩子,通过这些钩子可以方便我们操作js来实现过渡效果。

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  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>

这些钩子通常也是配合一些js动画库来实现动画效果。

多元素/多组件的过渡

1. 多元素的过渡

我们现在有两个button,我们希望通过点击on时,切换为off button。点击off时,切换为on button,这里就涉及到多个元素(button)的过渡了,一个需要显示出来,一个需要隐藏起来。 html结构如下:

    <transition name = "fade">
      <button  v-if = "status === 'off'" @click = "status='on'">on</button>
      <button  v-else @click = "status='off'" >off</button>
    </transition>

css如下:

.fade-enter-active,.fade-leave-active{
  transition: all 1s;
}
.fade-enter{
  opacity:0;
  background:red;
}
.fade-leave-to{
  opacity:0;
  background:red;
}

这里会出现两个问题:

  1. 多个元素可能会被vue识别为同一个元素,比如上文中的button由于只是内部文本的不同,切换时会被Vue只是识别成一个元素,只是内容的展示不同。但是实际上我们是要实现两个元素的过渡,因此为了避免这种情况,我们需要给每个过渡的元素设置不同的key值。
  2. Vue中多个元素的进入和离开的过渡同时发生的,这样的话会导致一些问题,比如隐藏的元素动画执行时间长,会占据需要显示的元素位置,影响动画效果,因此,我们希望多个元素能够按照先后顺序进行过渡,比如先隐藏再显示。Vue动画中提供了mode模式来设置控制多个元素的过渡。
    <transition name = "fade" mode="out-in">
      <button key = "on" v-if = "status === 'off'" @click = "status='on'">on</button>
      <button key = "off" v-else @click = "status='off'" >off</button>
    </transition>

mode="out-in"表示先执行离开的过渡,然后执行进入的过渡。
总结:
多个元素的过渡必须使用key来进行区分,需要设置mode来控制过渡模式。

2. 多组件的过渡

多组件的切换不需要使用key,可以通过使用component动态组件来实现。

<transition name="component-fade" mode="out-in">
  <component v-bind:is="view"></component>
</transition>

列表的过渡

目前为止,关于过渡我们已经讲到:

  • 单个节点
  • 同一时间渲染多个节点中的一个 我们之前说过在插入DOM,删除DOM和更新DOM时可以使用过渡,而列表也适用这种情况。列表是要在同一时间渲染多个DOM。在这种场景中,Vue提供了 <transition-group> 组件:
<div id="list-demo" class="demo">
  <button v-on:click="add">Add</button>
  <button v-on:click="remove">Remove</button>
  <transition-group name="list" tag="p">
    <span v-for="item in items" v-bind:key="item" class="list-item">
      
    </span>
  </transition-group>
</div>

列表的过渡:

  1. 必须使用transition-group标签。不同于 <transition>,它会以一个真实元素呈现:默认为一个 <span>。你也可以通过 tag 属性更换为其他元素。
  2. 循环的列表必须是transition-group的第一个子元素,中间不能有其他元素,否则无法生效。
  3. 列表内部元素必须提供唯一的key值。
  4. CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。css的过渡与之前的transition过渡写法相同。

总结

本文主要讲述了Vue中过渡/动画的使用,主要包括过渡的使用条件,单元素/组件的4中过渡/动画的实现方式,多元素/多组件的过渡实现方式以及列表的的过渡。虽然都是Vue中的一些基础API,但是了解了这些,才能够在开发过程中帮助我们更好地应用动画,从而实现一些酷炫的效果。

本文使用 mdnice 排版