前端复杂带交互动画的lottie-web方案实现

5,229 阅读5分钟

引言

在lottie出现之前,前端对动画往往是通过css自己手写。随着动画效果的日益复杂,一些动画效果存在兼容问题不说,有些也是复杂到难以实现,前端er要花很长时间在动效的coding上。

lottie-web的出现,解放了前端在动效上的生产力。然而,因为对lottie-web来说,动画的icon、字体、内容、效果、位置等关键信息都是存在于该lottie的json文件之中的。所以在采用lottie的方案中,很多是动效本身并不带有交互性质的,或者说是内容不变的。但对于动效本身存在交互、动效上的文字内容需要随着状态而变化的动画来说,json文件层级较深,操作更改json内容是不太方便的。

那有什么办法能实现可带交互的动画lottie呢?下面将对做本次活动遇到的动画场景及具体的动画方案进行详细介绍。

一、活动介绍

本次活动【翻牌领现金】属于考拉海购用户增长的业务之一。通过支付宝提现50元和150元的现金刺激,促使用户裂变活动,达到拉新的目的。

该活动为了增加用户的参与感和游戏感,对动效、交互的要求都比较高。对前端来说,纯css难以实现这种炫酷的动效,因此考虑采用lottie方案,下面会对该方案进行具体介绍。首先给出该活动的主要截图。

二、动画方案

动画效果如下图:

对于用户可以翻牌成团的情况,逐步播放发牌晃动着****等待翻牌翻牌的动画。该系列动画比较复杂,通过分析动画的连贯性、是否存在交互部分,把整个动画分为四个阶段,具体表现为:

  • 第一阶段:先在页面中间呈现一堆牌(7张)垒摞的效果,之后进行逐张的发牌动作。页面从上到下,从左到右平铺这7张牌。
  • 第二阶段:发完牌,所有的牌呈现一个水波纹的晃动,等待用户翻牌。
  • 第三阶段:用户点击了某张牌之后,所有牌归位不再波动。该张牌先进行翻牌的动效,并显示翻得的金额、过一段时间后,其他的牌也执行翻牌效果,显示其他牌的金额信息。
  • 第四阶段:用户翻的牌一边放大一边移动到页面中心位置,其他牌过渡效果下移并消失。

考虑到具体的动画效果(如牌的垒摞、牌的水波纹翻动、翻牌等)通过css可能会存在兼容或者难以实现的原因,因此整体上打算采用lottie进行实现。本文对lottie本身不进行赘述,具体可以点这里进行查看

在上述动画中,因为翻牌的牌面金额信息是由后端计算下发的,且用户所翻的牌是未知随机的,因此不可能通过简单的一个包含1-4全部阶段的lottie进行实现。所以打算采用分阶段多个lottie进行实现。

采用分阶段多个lottie的方案,可把上述四个阶段分解如下:

  • 第一、二阶段,不存在交互过程,因此使用一个发牌的lottie进行动画的播放。

  • 首先初始化发牌的lottie

this.cards=lottie.loadAnimation({
 path: 'http://xxxxxxx.json',container: this.$refs.card, // 发牌过程的dom
 renderer: 'svg',
 loop: true,
 autoplay: false
});
Copy
  • 初始化完毕,播放发牌和波动的动效
this.cards.addEventListener('data_ready', () => {
  this.cards.playSegments([0, 45], true);   // 0,45 为发牌阶段的帧数
});
this.cards.onLoopComplete = () => {
  this.cards.playSegments([45, 104], true);  // 45, 104 为水波纹晃动的帧数
};
Copy
  • 在第二阶段完成之后,通过定位,在发完牌的7张波动牌上分别叠加一个单张牌的lottie(仅画上可点击热区,还未在视图中展示单张牌的动画),初始化单张牌,等待翻牌。

    this.amounts.forEach((card, index) => {
     this.card[index] = lottie.loadAnimation({
      path: 'http://xxxxxxx.json',
      container: this.getRef(index), // 7张牌的dom
      renderer: 'svg',
      loop: false,
      autoplay: false
     });    
    });
    
    Copy
  • 第三阶段,点击牌的瞬间,执行以下事件:

1、网络请求,得到7张牌翻得的金额信息

2、隐藏第一二阶段的发牌lottie

3、显示上一步骤初始化的7张单牌lottie

4、所有的牌归位(即牌停止水波浮动,等待翻转的状态)。

5、通过lottieAPI,使点击的牌播放翻牌动效。

6、通过定时器,隔特定时间,执行播放其他牌的翻牌动效。

  • 点击后,进行网络请求,得到该次翻牌的金额。
  • // 所有牌归位
this.cards.goToAndStop(155, true);  // 155 为 牌归位的帧数
Copy
  • 执行牌的翻转动效。
// 点击的牌 翻转动画
this.card[i].playSegments([200, 210], true);  // 200-210 为执行翻牌的动画帧数
Copy
  • 通过定时器,让其他的牌也执行翻牌动效
setTimeout(() => {
  this.card[i].playSegments([200, 210], true);
}, 200);
Copy
  • 第四阶段,通过css3 animation进行过渡渐变。完成剩下的动效。

总结

对于本次的复杂带交互的动画效果,考虑采用lottie + 定时器 + css3 animation进行实现。

整体思路为分析动画效果、拆分动画阶段,区分可交互动画和纯展示动画的部分。对于需要交互的部分,隐藏叠加到纯展示动画lottie之上并留出可交互点击的区域热区。然后通过lottieAPI,在交互的时候播放关键帧,并操控纯展示动画的展示与否。最后通过css部分,对lottie无法实现的部分进行完善。

该项目采用这种方案实现,效果整体不错,达到视觉预期。提供一种思路给大家参考。