效果图:
用jQuery制作视频弹幕
左侧视频画面上显示弹幕,右侧评论区显示各用户发表过的评论,自己发表的评论也可显示在弹幕上。

基本布局

HTML:

<div id="myvideo">
    <!-- 视频区 -->
    <div id="video_area">
        <!-- 视频窗口 -->
        <div id="video_window">
            <!-- 视频 -->
            <video id="video" src="media/海草舞.mp4" width="500" preload="metadata"></video>
            <!-- 弹幕区,覆盖在视频窗口上 -->
            <div id="barrage_area" class="barrage_area"></div>
        </div>
        <!-- 进度条 -->
        <div class="myprogress"></div>
        <!-- 播放控件 -->
        <div id="mycontrols" class="mycontrols icon">
			<!-- 播放按钮 -->
			<div id="play" class="play">播放</div>
            <!-- 停止按钮 -->
            <div id="stop" class="stop">停止</div>
            <!-- 弹幕开关 -->
            <div id="on_off" class="barrage_icon">
            	<div>弹幕</div>
           </div>
           <!-- 时间 -->
           <div class="time_area">
                <span id="curTime"></span> / <span id="durTime"></span>
           </div>
           <!-- 屏宽 -->
           <div class="range_area"></div>
           <!-- 音量图标 -->
           <div id="horn" class="horn"></div>
        </div>
    </div>
    <!-- 评论区 -->
    <div id="comment_area" class="comment_area">
        <!-- 用户评论 -->
        <div id="comment" class="comment">
            <div id="comment_content"></div>
        </div>
        <!-- 发表评论 -->
        <div>
            <div><textarea id="mycomment" class="mycomment" rows="5" onfocus="select()"></textarea></div>
            <div style="text-align: right"><input id="comment_submit" type="button" value="评论"></div>
        </div>
    </div>
</div>

主要CSS:

#myvideo{
    display: flex;/*实例总体布局方式*/
}
/**** 视频区 ****/
#video_area{
    width: 500px;
    color: white;
    background-color: #000000;
    font-size: 20px;
    padding: 40px 40px 20px 40px;/*黑边大小*/
    flex: none;
}
#video_window{
    position: relative;
}
/**** 播放控制面板 ****/
.mycontrols{
	display: flex;
	justify-content: space-between;
	margin-top: 10px;
}
/** 弹幕 **/
@keyframes barrageAnimation{/*弹幕移动动画*/
    0%{
        right: 0;
        transform: translate(100%, 0);
    }
    100%{
        right: 100%;
        transform: translate(0, 0);
    }
}
.barrage_area{/*弹幕区*/
    position: absolute;/*叠放在视频窗口上*/
    top: 0;
    left: 0;
    width: 500px;/*初始大小*/
    height: 250px;
    overflow: hidden;
    background-color: RGBA(250,10,10,0.3);/*此颜色在调试时使用,完成后要删掉*/
}
.barrage_area div{/*弹幕文字样式*/
    position: absolute;
    right: 100%;/*从右侧进入*/
    font-size: 20px; /*弹幕文字大小*/
    color: #fefcc9;
    white-space: nowrap;
    text-shadow: 0 0 2px #999;
    animation: barrageAnimation ease-in 10s;
}
/**** 评论区 ****/
.comment_area{
    width: 280px;
    margin-left: 5px;
    flex: none;
    display: flex;
    flex-direction: column;/*内部为垂直布局*/
}
.comment{/*用户评论*/
    border: #66aaEE solid 1px;
    font-size: 14px;
    line-height: 20px;
    padding: 5px;
    overflow-y: auto;
    flex: auto;/*高度可自动扩展*/
}
.comment div{
    margin-top: 5px;/*评论间距*/
}
.comment span{
    color: #cd4606;/*用户名颜色*/
}
.mycomment{/*发表评论文本框*/
    width: 275px;
    margin-top: 5px;
}
/****弹幕开关图标****/
/*用例:
<div class="barrage_icon">
    <div>弹幕</div>
</div>
关闭状态需向class中添加off,即:class="barrage_icon off"
*/
.barrage_icon{/*圆角矩形*/
    position: relative;
    width: 40px;
    height: 20px;
    line-height: 20px;
    font-size: 12px;
    border-radius: 10px;
    background-color: darkcyan;
    padding: 0 5px;
    cursor: default;
}
.barrage_icon::after{/*圆形按钮*/
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    width: 20px;
    height: 20px;
    border-radius: 100%;
    background-color: #aaaaaa;
    background: radial-gradient(circle,#c0c0c0,#f1f1f1);
}
.barrage_icon.off{/*关闭状态*/
    background-color: #999999;
    text-align: right;
}
.barrage_icon.off::after{
    right: auto;
    left: 0;
}

效果图上的各种控件都是用CSS画的,量很大,这里只给出了与弹幕相关的。

弹幕数据

弹幕数据应来自于后台数据库,此处我们用一个JSON文件模拟从数据库中读取到的数据,结构如下:
barrage.json:

{
  "data":[
    {
      "time": 3.5,
      "username": "自强奋斗者协会",
      "text": "又一神曲"
    },
    {
      "time": 88.6,
      "username": "请叫我天才369号",
      "text": "现在才知道萧全是唱斗龙战士1主题曲的人"
    },
    {
      "time": 5.1,
      "username": "葫芦小紫",
      "text": "海草海草海草海草。。。"
    },
    {
      "time": 76.9,
      "username": "NONGZHENG",
      "text": "抛开成见,还是挺好听的"
    },
    {
      "time": 8,
      "username": "神兽驴蛋蛋儿",
      "text": "继社会摇之后又一神曲,萧全有毒!!!"
    },
    {
      "time": 20,
      "username": "fanfan",
      "text": "好听"
    },
    {
      "time": 20,
      "username": "小米",
      "text": "嗨起来,哈哈哈。。。"
    }
 ]
}

time是发布时间,是用户在观看视频时发布的,以秒数为单位,比如"time": 3.5表示用户在看到视频播到3.5秒时发布了此条评论。
username是用户名。
text是评论文本。

弹幕控制

几个要点:

  • 弹幕区要覆盖在视频上,大小与视频相同(调试时加了个红色背景,调试完记得要删掉)
  • 播放时用Ajax加载弹幕数据
  • 监听视频的timeupdate事件,保证弹幕出现的时间与视频播放时间同步
  • 弹幕出现的位置和移动的速度是随机的
  • 关闭弹幕不能用隐藏,它会导致再打开时积累的弹幕一起涌出,所以用修改不透明度的方式隐藏弹幕

JS代码:(需使用jQuery)

/**** 弹幕控制 ****/
var barrage = {
    data: [], //弹幕文本
    area_id: "#barrage_area", //弹幕区id
    area_width: 0, //弹幕区宽度
    area_height: 0, //弹幕区高度
    isLoad: false, //是否已加载弹幕数据
    isOn: true, //是否开启弹幕
    on_off_id: "#on_off", //弹幕开关id
    curTime: 0, //当前时间
    setBarrageArea: function (width,height) {//设置弹幕区大小
        this.area_width = width;
        this.area_height = height;
        $(this.area_id).css({"width":width+"px","height":height+"px"});//设置弹幕区大小
    },
    getData: function () { //获取弹幕文本
        var that = this;
        $.ajax({
            type: "GET",
            url: "js/barrage.json",//弹幕数据地址
            data: {},
            dataType: "json",
            success: function(res) {
                that.data = res.data;
                that.data.sort(function (a, b) {//按时间顺序排序
                    return a.time-b.time;
                });
                that.isLoad = true;
            }
        });
    },
    showBarrage: function () { //显示弹幕
        if(this.data.length==0) return;
        if(this.data[0].time>this.curTime) return;
        var text = this.data[0].text; //取出首条弹幕
        var top = Math.random()*(this.area_height-20);//随机生成弹幕文本位置
        var dt = 6;//速度基点
        if(this.area_width>600){
            dt += 2;
        }
        if(this.area_width>800){
            dt += 2;
        }
        if(this.area_width>1000){//大屏幕增加时间
            dt += 2;
        }
        var dmtime = Math.random()*10+dt;//随机生成弹幕过渡时间
        if(text.length>10){//长文本增加时间
            dmtime+=5;
        }
        if(text.length>20){
            dmtime+=4;
        }
        if(text.length>30){
            dmtime+=3;
        }
        var div = $("<div></div>").text(text).css({"top":top,"animation-duration":dmtime});
        $(this.area_id).prepend(div);//显示弹幕
        this.data.shift(); //从数组中删除已输出的弹幕
    },
    on_off: function () { //弹幕开关处理函数
        $(this.on_off_id).toggleClass("off");//切换开关状态
        if(this.isOn){
            $(this.area_id).css("opacity",0);//关闭弹幕
        }else {
            $(this.area_id).css("opacity",1);//打开弹幕
        }
        this.isOn = !this.isOn;
    }
};
barrage.setBarrageArea(500,280);//设置弹幕区大小

事件监听:

  • 单击播放按钮时加载弹幕数据
  • 单击停止按钮时清除弹幕数据,以便再次播放时可从头开始
  • 视频正常结束时也要清除弹幕数据
  • 单击弹幕开关时切换弹幕显示状态
  • 根据视频播放进度显示弹幕

JS代码:

//视频标签
var video = document.getElementById("video");

/** 单击播放按钮 **/
$("#play").click(function () {
	video.play();
    if(!barrage.isLoad){
        barrage.getData();//加载弹幕数据
        comment.clear();//清除评论区内容
    }
});
/** 单击停止按钮 **/
$("#stop").click(function () {
	video.pause();
    video.currentTime = 0;
    barrage.isLoad = false;
    barrage.curTime = 0;
});
/* 单击弹幕开关按钮 */
$("#on_off").click(function () {
    barrage.on_off();
});
/** 监听视频的ended事件 **/
document.getElementById("video").onended = function () {
    barrage.isLoad = false;
    barrage.curTime = 0;
};
/** 监听视频的timeupdate事件 **/
document.getElementById("video").ontimeupdate = function () {
    barrage.curTime = this.currentTime; //同步视频时间
    comment.append(); //添加到评论区
    barrage.showBarrage(); //显示弹幕
};

评论控制

评论与弹幕是同步的,而且评论带有用户名。
要点:

  • 加载弹幕时要清空评论区,以便再次播放时不会与上次重叠(见上面的单击播放按钮代码)
  • 评论显示与弹幕是同步的(见上面的timeupdate事件)
  • 评论区填满后要产生垂直滚动条,且要保证滚动条在底部,这样可以让评论向上滚动
  • 自己发布的评论在弹幕上显示(已实现),还要写入后台数据库,这样别人才能看到你发表的评论(未实现)

JS代码:

/**** 评论控制 ****/
var comment = {
    comment_area_id: "#comment_area",//评论区id
    comment_id: "#comment", //评论框id
    content_id: "#comment_content", //评论内容区id
    sub_id: "#mycomment", //评论文本框id
    subButton_id: "#comment_submit", //发布按钮id
    setCommentArea: function (width,height) {//设置评论区大小
        $(this.comment_area_id).css({"width":width,"height":height+115+"px"});
    },
    append: function () { //显示已有评论(数据在弹幕控制中)
        if(barrage.data.length==0) return;
        if(barrage.data[0].time>barrage.curTime) return;
        var div = $("<div></div>");//生成评论标签
        var span = $("<span></span>").text(barrage.data[0].username+":");
        div.append(span,barrage.data[0].text);
        $(this.content_id).append(div);//添加到评论内容区
        $(this.comment_id)[0].scrollTop = $(this.comment_id)[0].scrollHeight;//保持滚动条在最底部
    },
    subComment: function () { //发表评论
        if(!barrage.isLoad) return;
        var text = $(this.sub_id).val();//评论内容
        if(text.length==0) return;
        barrage.data.unshift({ //添加到弹幕数组中
            time: 0,//如果写入后台,需设置为视频当前时间video.currentTime
            username: "我",
            text: text
        });
    },
    clear: function () { //清空评论区
        $(this.content_id).html("");
    }
};
/*单击评论发布按钮*/
$(comment.subButton_id).click(function () {
    comment.subComment();
});
//设置评论区初始大小
comment.setCommentArea(280,250);

调试时要注意视频文件路径和json文件路径,弹幕和评论都必须在播放视频时才可用。

相关文章: