Web大作业(8)弹幕功能的实现

本文介绍如何使用HTML、Canvas和JavaScript实现视频弹幕功能,包括弹幕数组定义、CanvasBarrage类创建、弹幕渲染及用户交互。通过监听视频播放状态,确保弹幕随视频进度正确显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建一个html,在body部分写入:

<h1></h1>
    <div id="container">
        <div id="content">
            <canvas id="canvas" ></canvas>
            <video width="640px" height="360px" src="0001.mp4" controls id="video"></video>
        </div>
        <input type="text" id="text"> <button id="add">发射弹幕</button>
        <input type="color" id="color"> <input type="range" max="40" min="20" id="range">
    </div> 

0001.mp4是测试用视频。

下面实现弹幕功能,首先先写一个数组,数组中存放一些已经写好的弹幕:

let data = [
            {
                value : "哈哈哈哈哈哈哈",//内容
                speed : 2,//速度
                color : 'red',
                time : 0,//出现时间
                fontSize : 20
            },
            {
                value : "哈哈哈哈哈哈哈哈哈哈",//内容
                speed : 5,//速度
                time : 10,//出现时间
                fontSize : 20
            }
        ]

创建一个CanvasBarrage对象,用于把弹幕渲染到canvas画布上:

class CanvasBarrage{
            constructor(canvas,video,options={}){
                if(!canvas||!video) return;
                this.canvas = canvas;
                this.video = video;
                let defaultOptions = {
                    fontSize:20,
                    color:"gold",
                    speed:2,
                    opacity:0.9,
                    data:[]
                }
                Object.assign(this,defaultOptions,options);
                //获取画布
                this.context = canvas.getContext('2d')
                //设置登高
                this.canvas.width = video.clientWidth
                this.canvas.height = video.clientHeight
                //是否暂停
                this.isPause = true;
                //Barrage是弹幕的实例类
                this.barrages = this.data.map(obj=>new Barrage(obj,this));
                //渲染弹幕
                this.render();
            }

            renderBarrage(){
                //将数组中的弹幕一一取出,判断时间和视频的时间是否符合,符合就执行渲染
                let time = this.video.currentTime
                this.barrages.forEach(barrage => {
                    if(!barrage.flag && time>=barrage.time){
                        if(!barrage.isInited){
                            barrage.init();
                            barrage.isInited = true
                        }
                        barrage.x-=barrage.speed;
                        barrage.render();
                        if(barrage.x<=barrage.width*-1){
                            barrage.flag = true
                        }
                    }
                })
            }

            render(){
                //先清空
                this.context.clearRect(0,0,this.canvas.width,this.canvas.height)
                //渲染
                this.renderBarrage();
                if(this.isPause===false){
                    requestAnimationFrame(this.render.bind(this))
                }
            }
        }

为每一个弹幕创建一个barrage对象,两个方法,一个确定这个弹幕长啥样,主要是要求宽和高,另一个将其添加到画布上:

class Barrage{
            constructor(obj,ctx){
                this.value = obj.value
                this.time = obj.time
                this.obj = obj
                this.ctx = ctx
            }
            init(){
                this.opacity = this.obj.opacity||this.ctx.opacity;
                this.color = this.obj.color||this.ctx.color;
                this.fontSize = this.obj.fontSize||this.ctx.fontSize;
                this.speed = this.obj.speed||this.ctx.speed;

                //求自己的宽度
                let span = document.createElement('span')
                span.innerText = this.value;
                span.style.font = this.fontSize + 'px "Microsoft YaHei"';
                span.style.position = 'absolute'
                document.body.appendChild(span)
                //记录弹幕有多宽
                this.width = span.clientWidth
                document.body.removeChild(span)
                this.x = this.ctx.canvas.width
                this.y = this.ctx.canvas.height * Math.random();
                if(this.y < this.fontSize){
                    this.y = this.fontSize
                }
                if(this.y > this.ctx.canvas.height-this.fontSize){
                    this.y = this.ctx.canvas.height-this.fontSize
                }
            }
            render(){
                this.ctx.context.font = this.fontSize + 'px "Microsoft YaHei"';
                this.ctx.context.fillStyle = this.color;
                this.ctx.context.fillText(this.value,this.x,this.y);
            }
        }

确认视频是否在播放:

let Canvasbarrage = new CanvasBarrage(canvas,video,{
            data
        });
        video.addEventListener('play',function(){
            Canvasbarrage.isPause = false;
            Canvasbarrage.render()
        })
        video.addEventListener('pause',function(){
            Canvasbarrage.isPause = true;
        })

即:判断视频是否暂停,如果没有暂停就反复清空并渲染,对于每一条弹幕,如果发现该时刻有该弹幕出现,就把它渲染到页面上的随机高度,并且不断向左移动,如果完全跃出屏幕就将flag置为true,今后不再渲染。

然后实现发射弹幕功能,点击发射弹幕时执行函数Canvasbarrage.add:

add.addEventListener('click',function(){
            let value = document.getElementById("text").value
            let time = video.currentTime
            let color = document.getElementById("color").value
            let fontsize = document.getElementById("range").value
            let obj = {
                time,value,color,fontsize
            }
            Canvasbarrage.add(obj)
        })

为Canvasbarrage添加add方法:

add(obj){
            this.barrages.push(new Barrage(obj,this));
        }

然而如果把视频倒回去,原先该出现的弹幕就不再出现了,因此需要对此进行改进:

video.addEventListener("seeked",function(){
            Canvasbarrage.reset()
        })

为Canvasbarrage添加reset方法:

reset(){
                this.context.clearRect(0,0,this.canvas.width,this.canvas.height)
                let time = this.video.currentTime
                this.barrages.forEach(barrage => {
                    barrage.flag = false;
                    if(time<=barrage.time){
                        barrage.isInited = false;
                    }else{
                        barrage.flag = true;
                    }
                })
            }

如果往后调,无妨,往前调原先出现过的弹幕还要出现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值