借助Granimjs制作绚丽的流体动画

1,656 阅读4分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情

前言

Granim是什么?Granim是一个流体动画库,那么流体动画又是什么?流体动画就是渐变色不断地移动,我们看一个案例就知道了:

2022-09-05 22.03.56.gif

我们想要做一个流体动画按钮,有三种方式:

  1. 设计师制作lottie文件,前端直接播放
  2. 设计师制作GIF播放
  3. 前端用css模拟流体动画或者用canvas绘制动画

但是如果设计师不愿意做的话,我们只能自己想办法,用css模拟流体动画性能较好,但是代码成本很高,调试效果成本也很高,所以使用现成的动画库可能更符合我们的需求,那么我们就找到了Granimjs(怎么找到的Granimjs我们在文章最后揭晓)

Granimjs

官网效果很炫酷:sarcadass.github.io/granim.js/

官方文档:sarcadass.github.io/granim.js/a…

基础用法:

var granimInstance = new Granim({
    element: '#root',
    states : {
        "default-state": {
            gradients: [
                ['#834d9b', '#d04ed6'],
                ['#1CD8D2', '#93EDC7']
            ],
            transitionSpeed: 5000,
            loop: true
        }
    }
);

如果想像背景图一样写渐变色可以这样写,将之前的颜色字符串变为一个对象,这个对象里面有一个pos代表从上一个pos到这个pos是当前这个颜色

 gradients: 
[
  [
    { color: 'rgba(255, 153, 102, .33)', pos: .5 },
    { color: '#ff5e62', pos: 1 }, ...
  ], [
    { color: 'hsla(144, 100%, 47%, .75)', pos: .1 },
    { color: 'hsl(210, 96%, 46%)', pos: .6 }, ...
  ],
  ...
]

下面我们用Granim实现一个小需求

需求1:hover按钮时做动画

我们先实现一个小需求,这里有一个按钮,还有一块画布,我们现在需要hover按钮的时候让画布动起来

image.png

hover对应的事件是onmouseenteronmouseleave,那么我们就在按钮触发onmouseenter时初始化一个Granim对象:

<button onmouseenter="startGranim(this)">按钮</button>
<canvas id="root"></canvas>
<script src="https://cdn.bootcdn.net/ajax/libs/granim/2.0.0/granim.min.js"></script>
<script>
  window.onload = function () {
    var granimInstance;
    const root = document.getElementById('root')
    
    window.startGranim = () => {
      granimInstance = new Granim({
        element: root,
        states: {
          "default-state": {
            gradients: [
              ["#834d9b", "#d04ed6"],
              ["#1CD8D2", "#93EDC7"],
            ],
            transitionSpeed: 5000,
            loop: true,
          },
        },
      });
    };
  };
</script>

效果如下: image.png

这样的话我们还需要处理鼠标离开事件,我们知道hover时状态会进行一个切换,当离开之后状态立马回归到原始状态了,所以我们在鼠标离开时需要将动画销毁,其实也就是清除画布,这里我们有一个API可以直接调用

window.destroyGranim = () => {
      granimInstance.destroy();
};

紧接着我们想把这个动画效果添加到当前按钮身上去,这就是我们的需求2

需求2:将动画效果应用到按钮上

我们先稍微美化一下我们的按钮:

<style>
  .box{
    position: relative;
    width: 140px;
    height: 50px;
    line-height: 50px;
    text-align: center;
    background-image: linear-gradient(90deg,#834d9b,#d04ed6);
    color: white;
    font-size: 16px;
    border-radius: 8px;
    overflow: hidden;
  }
  .box span{
    position: relative;
    z-index: 1;
  }
  canvas{
    position: absolute;
    left: 0;
    top: 0;
    width: 140px;
    height: 50px;
  }
</style>
<div class="box" onmouseenter="startGranim(this)" onmouseleave="destroyGranim()">
  <span>hover出现动画</span>
  <canvas id="root"></canvas>
</div>

美化之后效果如图:

image.png

还是按照刚才的脚本来写,我们就可以得到一个拥有hover流体动画超能力的按钮,但是这还不够我们需要把这个按钮抽象为一个组件,以便在所有页面都能够使用到这个按钮

需求3:在React中抽象按钮组件

由于组件可能被多处复用,那么借助id获取元素的方式就不能使用了,所以我们需要借助React的ref来获取Dom元素,由于我们整个项目可能需要保持风格的一致性,所以对于动画的参数我们没有进行props传递:

后记

至此我们的流体动画告一段落,我们利用Granimjs实现了一个具备流体动效的按钮组件,但是请思考一下,如果我们不知道有Granimjs能够实现这个功能,我们想破头皮可能也做不出来,虽然网上有使用css去模拟流体动画的案例,但是那些都很差强人意

我在实践的过程中就是70%的时间在于寻找一款能够符合需求的动画库,而30%的时间用在了写代码上面;怎么样才能节省这个搜索的时间?

我们经常能够看到掘金上面有一些合集,当看到动画库合集时我们需要把它收藏起来让他吃灰,说不定有朝一日它就起了大作用