乐趣区

关于前端:腾讯课堂-H5-直播间点赞动效实现一CSS

1. 前言

以前在看微信视频号直播的时候,常常点击右下角的点赞按钮。看着它的数字缓缓从一位数变成五位数,还是挺有气氛感的。特地是长按的时候,有个手机触动的反馈,很带感。

尽管之前很好奇这些飘动的点赞动效是怎么实现的,但没有特地去钻研。直到前阵子投入腾讯课堂 H5 直播间的需要,须要本人去实现一个这样的成果时,才开始摸索。
先看看最初的成果:

相比视频号的点赞动效,轨迹简单了很多。能够看到课堂直播间的这一段点赞动效,大略分为这么三个阶段:

1. 从无到有,在回升过程中放大成失常大小
2. 回升过程中左右摇曳,且摇曳的幅度随机
3. 左右摇曳回升的过程中,渐隐并放大

在入手之前,我先想到了应用 CSS animation 去实现这种静止轨迹。在实现之后,又用 Canvas 重构了一版,优化了性能。
接下来咱们别离来看看这两种实现形式。

2. CSS 实现点赞动效

2.1 轨迹剖析

因为点赞动画是在一个二维立体上的,咱们能够将它的静止轨迹拆分为 x 轴 和 y 轴 上的两段。
在 y 轴 上非常简单,咱们的点赞图标会做一段垂直回升的匀速运动,从容器底部回升到容器顶部。
而 x 轴 上是左右摇曳的,用数学的角度说,是一段简谐运动。

但用 css 实现的时候,其实不必这么精密。为了简化计算,咱们能够用几个关键帧来串联这段静止轨迹,例如:

@keyframes bubble_swing {
 0% {两头}
 25% {最左}
 75% {最右}
 100% {两头}
}

2.2 轨迹设计

依据下面的剖析,咱们能够设计一段雷同的回升轨迹,以及几段不同的左右摇曳轨迹。
回升轨迹很简略,同时咱们还能够加上透明度(opacity)、大小(transform)的变动,如下:

@keyframes bubble_y {
 0% {transform: scale(1);
   margin-bottom: 0;
   opacity: 0;
 }
 5% {transform: scale(1.5);
   opacity: 1;
 }
 80% {transform: scale(1);
   opacity: 1;
 }
 100% {margin-bottom: var(--cntHeight);
   transform: scale(0.8);
   opacity: 0;
 }
}

其中,–cntHeight 指的是容器的高度。也就是说,咱们通过让 margin-bottom 一直增大,来控制点赞图标从容器底部回升到容器顶部。
而对于横向静止的轨迹,为了减少静止轨迹的多样性,咱们能够设计多段左右摇曳的轨迹,比如说一段“两头 -> 最左 -> 两头 -> 最右”的轨迹:

@keyframes bubble_swing_1 {
 0% {
   // 两头
   margin-left: 0;
 }
 25% {
   // 最左
   margin-left: -12px;
 }
 75% {
   // 最右
   margin-left: 12px;
 }
 100% {margin-left: 0;}
}

这里同样应用 margin 来管制图标的左右挪动。相似的,咱们还能够设计几段别的轨迹:

// 任意轨迹
@keyframes bubble_swing_2 {
 0% {
   // 两头
   margin-left: 0;
 }
 33% {
   // 最左
   margin-left: -12px;
 }
 100% {
   // 随机地位
   margin-left: 6px;
 }
}

// 简谐反向
@keyframes bubble_swing_3 {
 0% {
   // 两头
   margin-left: 0;
 }
 25% {
   // 最右
   margin-left: 12px;
 }
 75% {
   // 最左
   margin-left: -12px;
 }
 100% {margin-left: 0;}
}

接下来咱们把 x 轴 和 y 轴 的轨迹(@keyframes)联合起来,并设置一个随机的动画工夫,比如说:

@for$i from 1 through 3 {
  @for$j from 1 through 2 {.bl_#{$i}_#{$j} {animation: bubble_y calc(1.5s + $j * 0.5s) linear 1 forwards,
       bubble_swing_#{$i} calc(1.5s + $j * 0.5s) linear 1 forwards;
   }
 }
}

这里生成了 3 * 2 = 6 种不同的轨迹。针对这类反复的选择器,用 SCSS 中的循环语法,能够少写很多代码。

2.3 随机抉择图片(雪碧图)

咱们每次点赞会呈现不同的图标,于是这里设计了一系列选择器给不同的图标,让它们出现不同的图片。首先咱们要筹备一张雪碧图,放弃所有图标的大小统一,而后同样应用 SCSS 的循环语法:

@for$i from 0 through 7 {.b#{$i} {background: url('../../images/like_sprites.png') calc(#{$i} * -24px) 0;
 }
}

像下面生成了 8 个选择器,咱们在程序执行时就能够随机给图标赋予一个选择器。

2.4 生成一个点赞图标

CSS 的局部差不多了,咱们当初来看 JS 是怎么执行的。咱们须要有一个容器 div,让它来装载要生成的点赞图标。以及一个按钮来绑定点击事件:

const cacheRef = useRef<LikeCache>({
   bubbleCnt: null,
   likeIcon: null,
   bubbleIndex: 0,
   timer: null,
});

useEffect(() => {cacheRef.current.bubbleCnt = document.getElementById('like-bubble-cnt');
   cacheRef.current.likeIcon = document.getElementById('like-icon');
}, []);

在点击事件中,生成一个新的 div 元素,并为它设置 className。接着将它 append 到容器下,最初在一段时间后销毁这个点赞图标元素。如下:

/**
* 增加 bubble
*/
const addBubble = () => {const { bubbleCnt} = cacheRef.current;

 cacheRef.current.bubbleIndex %= maxBubble;
 const d = document.createElement('div');

 // 图片类 b0 - b7
 // 随机动画类 bl_1_1 - bl_3_2
 const swing = Math.floor(Math.random() * 3) + 1;
 const speed = Math.floor(Math.random() * 2) + 1;
 d.className = `like-bubble b${cacheRef.current.bubbleIndex} bl_${swing}_${speed}`;

 bubbleCnt?.appendChild(d);
 cacheRef.current.bubbleIndex++;

 // 动画完结后销毁元素
 setTimeout(() => {bubbleCnt?.removeChild(d);
 }, 2600);
};

到这里,咱们就实现得差不多了。不过,咱们还能够给点击的图标加点动画,让它有一个被按压后弹起的成果:

/**
* 点击“喜爱”*/
const onClick = () => {const { timer, likeIcon} = cacheRef.current;
if (!likeIcon) {return;}

 if (timer) {clearTimeout(timer);
   cacheRef.current.timer = null;
 }
 likeIcon.classList.remove('bounce-click');
 // 删除并从新增加类,须要提早增加
 setTimeout(() => {likeIcon.classList.add('bounce-click');
 }, 0);
 cacheRef.current.timer = window.setTimeout(() => {likeIcon.classList.remove('bounce-click');
   clearTimeout(timer!);
   cacheRef.current.timer = null;
 }, 300);

 addBubble();};

2.5 最终成果

最初来看看成果吧!

明天就到这, 下期给大家分享 canvas 实现点赞动效的形式
❤️欢送大家关注我, 文章小白上路, 你们是我持续整顿分享的能源❤️
❤️公众号: 前端别搞我❤️

❤️关注 + 点赞珍藏 + 评论 + 分享❤️,手留余香,谢谢🙏大家。

退出移动版