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实现点赞动效的形式
❤️欢送大家关注我,文章小白上路,你们是我持续整顿分享的能源❤️
❤️公众号: 前端别搞我❤️
❤️关注+点赞珍藏+评论+分享❤️,手留余香,谢谢大家。