使用anime.js构建动画

yellowrabbit 发布于21天前 •最后由 nana10天前回复
3 条问题

之前有调研过动画实现的方式,以及动画的种类(传送门:前端动画调研)。最近好好研究了一下svg的使用,在研究svg的同时又萌生了制作svg动画的想法,于是今天上场的主角就是使用JS驱动的动画库anime.js。文章前部分主要介绍使用anime.js完成对DOM元素的动画制作,后半部分会简单介绍一下anime.js与svg如何搭配使用。

1.Anime.js

Anime.js是简单,强大的轻量级JavaScript动画库,它可作用于css 属性,SVG,DOM 属性 以及JavaScript对象。根据官方的这段介绍,可以看出其对Canvas绘制是并不支持的,如果你需要对Canvas进行深度操作,推荐查看PixiJSCreateJS。通过anime.js我们可以使用js去编写原本需要在css中书写很长的keyframes,也可以通过使用timeline来同时处理多个元素的动画效果,这一切都不需要再编写css。看一段简单的代码:

// 引入animejs
import anime from 'animejs/lib/anime.es.js';

// 初始化anime方法,即可对指定元素激活动画效果
anime({
  targets: 'div',
  translateX: 250,
  rotate: 360,
  backgroundColor: '#FFF',
  duration: 800
});

上述代码的意味着,当调用anine()方法时,便将所有的div标签立即执行向右移动250px,同时旋转360deg,并将颜色同时修改为白色,整个动画持续800ms。需要注意的是,targets默认使用document.querySelectorAll(),所以这里所有的div标签都会注入刚才定义的动
通过这段代码是不是觉得定义一个动画非常的简单,有种将css代码放入JS对象中的感觉。那么anime.js是如何实现关键帧keyframes,接着往下看。

2.keyframes关键帧

在css中,我们可以通过transition实现线性的动画,通过设置duration以及作用的元素,即可实现一段简单的如放大缩小动画。
https://jsfiddle.net/o02yda5j/
然而如果需要实现更加复杂的非线性多段动画,必然要使用animations,借助@keyframes也可以实现较为复杂的动画,这里有个简单栗子
https://jsfiddle.net/o02yda5j/
在这段代码中,我们将动画设置为4帧,translate分别在每一帧中定义一次,如果使用anime.js声明多帧将变得非常简单且清晰:

anime({
    targets: 'div',
    translateX: [
        { value: 200 },
        { value: 200 },
        { value: 0 },  // 第三帧
        { value: 0 },
    ],
    translateY: [
        { value: 0 },
        { value: 100 },
        { value: 100 },  // 第三帧
        { value: 0 },
    ],
})

我们还可以在每一帧定义持续时间,延时,以及贝塞尔曲线。如果没有对每一帧定义持续时间duration,该帧将会与其他未声明duration的帧平分animation的duration。不知道你是否注意到,通过在每一帧设置不同的延时delay,配合不同的css属性,将会很轻松就实现非常复杂的动画。不过缺点也非常明显,就是需要计算每一帧的duration+delay对下一帧的影响,因为动画本身就是不同的元素在不同的节点发生的变形构建的。即便如此,在anime.js手动计算两者对下一帧的影响,依然要比@keyframes写法更为高效直观。如下代码可以实现一个小球以不同的贝塞尔曲线进行矩形运动。

anime({
  targets: '.property-keyframes-demo .el',  // 指定动画元素,省去了css多少的代码...
  translateX: [ // 只参与两帧,需要注意,每个css属性不要求帧数都一样
    { value: 250, duration: 1000, delay: 500 },
    { value: 0, duration: 1000, delay: 500 }
  ],
  translateY: [
    { value: -40, duration: 500 },
    { value: 40, duration: 500, delay: 1000 },
    { value: 0, duration: 500, delay: 1000 }
  ],
  scaleX: [
    { value: 4, duration: 100, delay: 500, easing: 'easeOutExpo' },  // 第一帧发生在动画开始的500ms后,持续时间为100ms,贝塞尔曲线为easeOutExpo
    { value: 1, duration: 900 },
    { value: 4, duration: 100, delay: 500, easing: 'easeOutExpo' },
    { value: 1, duration: 900 }
  ],
  scaleY: [
    { value: [1.75, 1], duration: 500 },
    { value: 2, duration: 50, delay: 1000, easing: 'easeOutExpo' },
    { value: 1, duration: 450 },
    { value: 1.75, duration: 50, delay: 1000, easing: 'easeOutExpo' },
    { value: 1, duration: 450 }
  ],
  rotate: [
    { value: 1.2 },
  ],
  width: [
    { value: 200 },
  ],
  easing: 'easeOutElastic(1, .8)',
  loop: true
});

但是anime的keyframes也不是万能的,如果你的动画写的足够复杂,那么势必帧数就要增大,再加上多个css属性在每一帧如果都有体现,如上图,计算同一属性的不同帧,以及不同属性的不同帧,将会异常困难。因为你总是无法准确统计每一帧duration+delay对其他帧的影响,加入你想修改某一帧的duration,你就需要修改整个动画的受其影响的每一帧。如何解决,我们引入timeline,将复杂动画的过程以时间线的形式进行切片,分段处理。换句话讲使用timeline,将动画由串型改为并行。下图表示不同属性不同帧的执行情况,水平黑线表示duration,其白色间隔为delay延时。

image.png

3.Timeline 时间线

查看原文:

  • redcat
  • crazydog
  • organicwolf
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。