Vue:动画原理

概述

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。包括以下工具:

  • 在 CSS 过渡和动画中自动应用 class
  • 可以配合使用第三方 CSS 动画库,如 Animate.css
  • 在过渡钩子函数中使用 JavaScript 直接操作 DOM
  • 可以配合使用第三方 JavaScript 动画库,如 Velocity.js

在这里,我们只会讲到进入、离开和列表的过渡,你也可以看下一节的管理过渡状态

单元素 / 组件的过渡

transition的封装组件

过渡的类名

Transition Diagram

  • v-enter
  • v-enter-active
  • v-enter-to
  • v-leave
  • v-leave-active
  • v-leave-to

注意:如果<transition>没有名字,则v-是这些类名的默认前缀。如果像下面示例中,使用<transition name="fade">,那么v-enter就会替换为fade-enter

类名示例

效果

76.1.1.gif

这个示例中,.fade-ernter.fade-enter-active先被添加,随后立即删除.fade-enter,并添加.fade-enter-to,enter进程结束后,一起删除.fade-enter-active.fade-enter-to

CSS过渡

常用的过渡都是CSS过渡

CSS过渡示例

效果

76.1.2.gif

CSS动画

CSS动画和CSS过渡用法相同,区别是动画中v-enter类名在节点插入DOM后不会立即删除,而是在animationed事件触发时删除

CSS动画示例

效果

76.1.3.gif

自定义过渡的类名

可以通过attribute来自定义过渡类名:

  • enter-class
  • enter-active-class
  • enter-to-class
  • leave-class
  • leave-active-class
  • leave-to-class

注意,自定义过渡类名,优先级高于普通类名

还可以使用第三方CSS动画库,如Animate.css

使用Animate.css动画库

效果

76.3.1.gif

同时使用过渡和动画

Vue 的事件监听器可以是transitionedanimationed,取决于给元素应用的CSS规则。

但在一些场景中,需要给同一个元素同时设置两种过渡动效。transitionanimation结束时间不一样,需要使用type attribute 并设置 animationtransition来声明需要Vue监听的类型。

显性的过渡持续时间

在很多情况下,Vue 可以自动得出过渡效果的完成时机。默认情况下,Vue 会等待其在过渡效果的根元素的第一个 transitionendanimationend 事件。然而也可以不这样设定——比如,我们可以拥有一个精心编排的一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。

在这种情况下你可以用 <transition> 组件上的 duration prop 定制一个显性的过渡持续时间 (以毫秒计):

<transition :duration="1000">...</transition>
复制代码

你也可以定制进入和移出的持续时间:

<transition :duration="{ enter: 500, leave: 800 }">...</transition>
复制代码

JavaScript 钩子

可在 attribute 中声明 JavaScript 钩子

钩子函数 结合 CSS

这些钩子函数可以结合 CSS transitions / animations 使用,也可以单独使用。

JavaScript 函数 结合 transitions 使用示例

效果

76.3.2.gif

JavaScript 过渡

注意

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

Velocity 和 jQuery.animate 的工作方式类似,也可以用来实现 JavaScript 动画

一个使用 Velocity.js 的简单例子

效果

76.3.3.gif

多个元素的过渡

key

先看一个示例-使用key

效果

76.4.1.gif

对于多个元素的过渡,可以使用v-if / v-else

但当有相同标签名的元素切换时,需要通过key设置唯一的值来标记以让Vue区分,否则Vue为了效率只会替换相同标签内部的内容。

上面的示例就正确使用了key,如果不加key的话,就会默认替换标签内部的onoff,效果如下。

76.4.2.gif

使用多个v-if的多个元素的过渡可以重写为绑定了动态 property 的单个元素过渡。

<transition>
  <button v-if="docState === 'saved'" key="saved">
    Edit
  </button>
  <button v-if="docState === 'edited'" key="edited">
    Save
  </button>
  <button v-if="docState === 'editing'" key="editing">
    Cancel
  </button>
</transition>
复制代码

可以重写为

<transition>
  <button v-bind:key="docState">
    {{ buttonMessage }}
  </button>
</transition>
复制代码
// ...
computed: {
  buttonMessage: function () {
    switch (this.docState) {
      case 'saved': return 'Edit'
      case 'edited': return 'Save'
      case 'editing': return 'Cancel'
    }
  }
}
复制代码

过渡模式

还有一个问题,上面使用了key的示例,在on按钮和off按钮的过渡中,两个按钮都被重绘了,一个离开过渡的时候,另一个开始进入过渡。这是<transition>的默认行为——进入和离开同时发生。

76.4.1.gif

因此提供了过渡模式:

  • in-out:新元素过渡 => 当前元素过渡离开
  • out-in:当前元素过渡 => 新元素过渡进入

现在用out-in重写之前的开关按钮过渡:

<transition name="fade" mode="out-in">
  <!-- ... the buttons ... -->
<transition>
复制代码

效果

76.4.3.gif

in-out实现轮播效果

76.4.4.gif

多个组件的过渡

多个组件的过渡更简单,不需要key,相反,只需要使用动态组件

示例-组件过渡

效果

76.4.5.gif

列表过渡

使用<transition-group>组件,同时渲染整个列表。

组件特点:

  • 不同于<transition>,它会以一个真实元素呈现:默认为一个<span>。也可以通过tag更换为其他元素。
  • 过渡模式不可用,因为不再相互切换特有的元素。
  • 内部元素总是需要提供唯一的key值。
  • CSS过渡的类将会应用在内部的元素中,而不是这个组 / 容器本身。

列表的进入 / 离开过渡

示例

效果

76.5.1.gif

这个例子中,当添加和移除元素的时候,周围的元素会瞬间移动到他们的新布局的位置,而不是平滑的过渡,下面来解决这个问题。

列表的排序过渡

示例

效果

76.5.2.gif

<transition-group>组件不仅可以进入和离开动画,还可以改变定位。

Vue使用了一个叫FLIP简单的动画队列,使用transforms将元素从之前的位置平滑过渡到新的位置。

现在将这个技术和之前的示例结合,使列表的一切变动都有动画过渡。

示例

效果

76.5.3.gif

注意!使用FLIP过渡的元素不能设置为display: inline,作为替代方案,可以设置为display: inline-block,或放置于flex中。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享