在Vue中如何实现简单的动画效果

315 阅读4分钟

闲来无聊看看vue官网,发现一个有趣的东西,如何在vue里做一些简单的动画效果?vue已经为我们提前做好了方案,就是vue的内置组件Transition和TransitionGroup(目前先对Transition的使用做出记录)。可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发:

  • 由 v-if 所触发的切换
  • 由 v-show 所触发的切换
  • 由特殊元素 <component> 切换的动态组件

CSS方法实现动画效果

当一个 <Transition> 组件中的元素被插入或移除时,会发生下面这些事情:

  1. Vue 会自动检测目标元素是否应用了 CSS 过渡或动画。如果是,则一些 CSS 过渡 class 会在适当的时机被添加和移除。
  2. 如果有作为监听器的 JavaScript 钩子,这些钩子函数会在适当时机被调用。
  3. 如果没有探测到 CSS 过渡或动画、也没有提供 JavaScript 钩子,那么 DOM 的插入、删除操作将在浏览器的下一个动画帧后执行。

css的过渡和动画

CSS 的 transition

使用transition对元素动画进行css设置,vue默认需要设置为v-enter-from、v-leave-to、v-enter-active、v-leave-active、v-leave-from、v-leave-to,它们分别对应元素的初始形态、最终形态、过渡过程中、消失初始状态、消失最终状态。

<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>

    <transition>
      <h2 v-if="isShow">Hello World</h2>
    </transition>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        isShow: true
      }
    }
  }
</script>

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

  .v-enter-to, 
  .v-leave-from {
    opacity: 1;
  }

  .v-enter-active,
  .v-leave-active {
    transition: opacity 2s ease;
  }
</style>

css过渡class过渡效果命名也可以自行设置,通过给 <Transition> 组件传一个 name prop 来声明一个过渡效果名,具体代码如下:

<Transition name="fade"> 
... 
</Transition>
.fade-enter-active, 
.fade-leave-active { transition: opacity 0.5s ease; } 
.fade-enter-from, 
.fade-leave-to { opacity: 0; }

CSS 的 animation

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

对于大多数的 CSS 动画,我们可以简单地在 *-enter-active 和 *-leave-active class 下声明它们。下面是一个示例:

<Transition>
  <p v-if="show" style="text-align: center;">
    Hello here is some bouncy text!
  </p>
</Transition>

.v-enter-active {
  animation: bounce-in 0.5s;
}
.v-leave-active {
  animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.25);
  }
  100% {
    transform: scale(1);
  }
}

同时使用 transition 和 animation

Vue 需要附加事件监听器,以便知道过渡何时结束。可以是 transitionend 或 animationend,这取决于你所应用的 CSS 规则。如果你仅仅使用二者的其中之一,Vue 可以自动探测到正确的类型。

然而在某些场景中,你或许想要在同一个元素上同时使用它们两个。举例来说,Vue 触发了一个 CSS 动画,同时鼠标悬停触发另一个 CSS 过渡。此时你需要显式地传入 type prop 来声明,告诉 Vue 需要关心哪种类型,传入的值是 animation 或 transition

<Transition type="animation">
...
</Transition>

除了通过css的方式实现动画效果,js同样可以实现

jS方法实现动画效果

<Transition
  @before-enter="onBeforeEnter"
  @enter="onEnter"
  @after-enter="onAfterEnter"
  @enter-cancelled="onEnterCancelled"
  @before-leave="onBeforeLeave"
  @leave="onLeave"
  @after-leave="onAfterLeave"
  @leave-cancelled="onLeaveCancelled"
>
  <!-- ... -->
</Transition>
export default {
  // ...
  methods: {
    // 在元素被插入到 DOM 之前被调用
    // 用这个来设置元素的 "enter-from" 状态
    onBeforeEnter(el) {},

    // 在元素被插入到 DOM 之后的下一帧被调用
    // 用这个来开始进入动画
    onEnter(el, done) {
      // 调用回调函数 done 表示过渡结束
      // 如果与 CSS 结合使用,则这个回调是可选参数
      done()
    },

    // 当进入过渡完成时调用。
    onAfterEnter(el) {},
    onEnterCancelled(el) {},

    // 在 leave 钩子之前调用
    // 大多数时候,你应该只会用到 leave 钩子
    onBeforeLeave(el) {},

    // 在离开过渡开始时调用
    // 用这个来开始离开动画
    onLeave(el, done) {
      // 调用回调函数 done 表示过渡结束
      // 如果与 CSS 结合使用,则这个回调是可选参数
      done()
    },

    // 在离开过渡完成、
    // 且元素已从 DOM 中移除时调用
    onAfterLeave(el) {},

    // 仅在 v-show 过渡中可用
    onLeaveCancelled(el) {}
  }
}

这些钩子可以与 CSS 过渡或动画结合使用,也可以单独使用。 仅使用由 Js 执行的动画时,最好是添加个 :css="false" prop。这样 Vue 表明可以跳过对 CSS 过渡的自动探测。对性能做到了优化。有了 :css="false" 后,我们就可以自己控制什么时候过渡结束了。这种情况下我们需要注意,对于 @enter 和 @leave 钩子来说,回调函数 done 就是必须的。否则,钩子将被同步调用,过渡将立即完成。

过渡模式

在之前的例子中,进入和离开的元素都是同时开始动画的,因此我们需要将它们设为 position: absolute 以避免二者同时存在时出现的布局问题。

然而,很多情况下这可能并不符合需求。我们可能想要先执行离开动画,然后在其完成之后再执行元素的进入动画。手动编排这样的动画是非常复杂的,好在我们可以通过向 <Transition> 传入一个 mode prop 来实现这个行为:

<Transition name="fade" mode="out-in"> 
    <component :is="activeComponent"></component> 
</Transition>