吊打全网的高性能弹幕效果封装(Canvas + 原生JS)

2,348 阅读3分钟

前言

  1. 6000+门店使用的大屏,主机配置竟然是Android5.5 + Chrome 78,不支持es6。。。
  2. 随随便便一个css动画都可以把页面卡成ppt。
  3. 开发只给两天。。。
  4. buff叠满,还想在页面中做websocket,实现弹幕满屏播放功能。。。

调研尝试了一下,考虑了repaint等因素,用了css的transform:tanslate属性,页面只有两个div在移动页面都卡,无语了,甚至还开启了gpu加速transform:tanslateZ,一样卡成ppt,真的是delay no more

无奈之下,尝试了自己最不熟悉的Canvas,没想到竟然如此丝滑,把元素调成100个也丝毫不影响性能。

方案有了,下楼买杯瑞幸就是干!!!

image.png 大家逛街时估计都见过吧哈哈哈

核心优势

Canvas绘图

  1. 批量渲染:可以在一次绘制循环中处理所有弹幕,减少浏览器重绘次数。
  2. 内存效率:不需要为每个弹幕创建DOM元素,降低内存使用。
  3. 灵活性:可以轻松实现复杂的视觉效果和碰撞检测。

requestAnimationFrame

function animate() {
    // 更新弹幕位置
    updateBarrages();
    // 渲染弹幕
    renderBarrages();
    // 循环调用
    requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

setTimeoutsetInterval相比,requestAnimationFrame有以下优势:

  1. 与显示器刷新率同步,通常是60fps,减少丢帧。
  2. 在标签页不可见时自动暂停,节省资源。
  3. 允许浏览器优化并合并多个动画操作,提高性能。

队列虚拟列表:突破性能瓶颈

为了处理大量弹幕,实现了一个队列虚拟列表:

class CanvasBarrage {
    // ...其他代码

    handleBarrageRenderList() {
        // 移除已经离开屏幕的弹幕
        this.barrageList = this.barrageList.filter(item => !item.isExit);

        // 添加新的弹幕到渲染列表
        let addList = this.handleBarrageOriginList(this.barrageOriginList);
        addList = this.handleBarragePosition(addList);
        this.barrageList = this.barrageList.concat(addList);

        this.barrageCleanCount = 0;
    }
}

优势包括:

  1. 内存优化:只保留屏幕上可见的弹幕对象,大幅减少内存使用。
  2. 渲染优化:每帧只需要处理有限数量的弹幕,显著提升渲染性能。
  3. 无限循环:当所有原始弹幕都被使用后,列表会从头开始重新使用,实现无限弹幕效果。

自适应

支持px到vw的转换,使弹幕在不同屏幕尺寸下都能正常显示。

使用介绍

配置参数

以下是CanvasBarrage类的主要配置参数:

参数名类型默认值描述
idstringnull容器元素的选择器
barrageListIBarrageItem[][]初始弹幕列表
barrageRownumber5弹幕行数
barrageSpacenumber50弹幕间隔
toVwbooleanfalse是否转换为vw单位
basePxnumberclientWidth基准像素值
renderSizenumber50渲染size
fontSizenumber20字体大小
fontFamilystring'Arial'字体族
isRandomFontColorbooleanfalse是否使用随机字体颜色
fontColorstring'black'字体颜色
barrageSpeednumber1弹幕速度
renderOverLimitnumber20渲染超出限制数量
maxLimitnumber200最大渲染数量

使用方法

const barrageSystem = new CanvasBarrage({
  id: '#video-container',
  barrageList: initialBarrages,
  barrageRow: 10,
  fontSize: 24,
  isRandomFontColor: true
});

barrageSystem.drawBarrage();

// 添加新弹幕
barrageSystem.addBarrage([{ value: '新弹幕内容' }]);

效果

因为移除了UI,给大家自定义化,所以效果是最原始样式

image.png

源码

记得点一个star

Github链接

END

  • 大家可以在评论区讨论一下为什么用Canvas渲染会比CSS好
  • 希望这篇文章可以帮助到有需要的小伙伴们,有问题可以评论或私信我呀🤞🤞