美文网首页
腾讯课堂 H5 直播间点赞动效实现一(CSS)

腾讯课堂 H5 直播间点赞动效实现一(CSS)

作者: 吃辣舒服斯基 | 来源:发表于2022-02-23 11:43 被阅读0次

    1. 前言

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

    image

    虽然之前很好奇这些飘动的点赞动效是怎么实现的,但没有特别去钻研。直到前阵子投入腾讯课堂 H5 直播间的需求,需要自己去实现一个这样的效果时,才开始摸索。

    先看看最后的效果:

    image

    相比视频号的点赞动效,轨迹复杂了很多。可以看到课堂直播间的这一段点赞动效,大概分为这么三个阶段:

    从无到有,在上升过程中放大成正常大小

    上升过程中左右摇曳,且摇曳的幅度随机

    左右摇曳上升的过程中,渐隐并缩小

    在动手之前,我先想到了使用CSS animation去实现这种运动轨迹。在完成之后,又用Canvas重构了一版,优化了性能。

    接下来我们分别来看看这两种实现方式。

    2. CSS 实现点赞动效

    2.1 轨迹分析

    由于点赞动画是在一个二维平面上的,我们可以将它的运动轨迹拆分为x 轴y 轴上的两段。

    y 轴上非常简单,我们的点赞图标会做一段垂直上升的匀速运动,从容器底部上升到容器顶部。

    x 轴上是左右摇曳的,用数学的角度说,是一段简谐运动。

    image

    但用 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 最终效果
    最后来看看效果吧!

    微信图片_20220223111349.gif

    今天就到这,下期给大家分享canvas实现点赞动效的方式

    ❤️欢迎大家关注我,文章小白上路,你们是我继续整理分享的动力❤️

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

    相关文章

      网友评论

          本文标题:腾讯课堂 H5 直播间点赞动效实现一(CSS)

          本文链接:https://www.haomeiwen.com/subject/widolrtx.html