9

前言

就在最近这几年,弹幕这个东西慢慢地流行了起来。我们在网上看视频或者看直播都能见到弹幕的身影,有时候弹幕的内容甚至比视频本身内容还要精彩。本人也是很喜欢弹幕这个东西,看到精彩处刷个弹幕都是常事。正好最近也比较空闲,于是就自己写了一个Demo来展示一下弹幕效果的实现原理。不足之处,欢迎留言指教。

实现原理

项目结构

图片描述

项目结构非常简单,非常标准的html+css+js的结构。这里我们用了第三方的jQuery库来帮助我们完成这个弹幕效果。如果有兴趣的话,可以尝试一下用原生js去实现这个功能,看完这篇文章相信你也可以轻轻松松地用原生js实现。

HTML和CSS文件内容

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>弹幕墙</title>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div class="screen_container"></div>
    <div class="screen_toolbar">
        <input id="screenBulletText" type="text" placeholder="请输入弹幕内容"/>
        <button class="send">发射</button>
        <button class="clear">关闭弹幕</button>
    </div>
</body>
<script src="./jquery-3.2.1.min.js"></script>
<script src="./main.js"></script>
</html>

这里我们页面的布局非常简单,主要分为上下两个div:

  1. div.screen_container作为我们的弹幕墙,这里将会放我们发射的弹幕内容。

  2. div.screen_toolbar包含一个输入框用于输入我们需要发射的弹幕内容、一个发射按钮和一个关闭弹幕按钮。

另外就是引入第三方库以及我们自己的css和js。

CSS

.screen_container{
    position: relative;
    width: 600px;
    height: 400px;
    margin: 30px auto;
    background: #000;
    overflow: hidden;
}
.screen_toolbar{
    width: 600px;
    margin: 20px auto;
    text-align: center;
}

CSS的来稍微美化一下我们的布局,这里不设置我们的弹幕的样式。

HTML+CSS效果图

图片描述

JS实现

弹幕总体实现原理

弹幕的实现原理非常简单,我们点击”发射“按钮,就根据输入的弹幕的内容生成一个div插入div.screen_container中,并随机初始化我们生成的div的位置。这样我们的弹幕墙中就有一个我们自己生成的弹幕了,但是此时的弹幕还没有移动效果,需要给它加个定时任务,递减弹幕的CSS属性left的值,就可以实现移动效果。最后当弹幕移出弹幕墙的时候,销毁一下弹幕。整个弹幕效果实现过程大致就是这样,是不是很简单!

分段实现弹幕效果。

1. 根据指定内容生成弹幕,并初始化其位置以及其样式,插入div.screen_container中。
function createScreenbullet(text) {
    var jqueryDom = $("<div class='bullet'>" + text + "</div>");
    var fontColor = "rgb(" + Math.floor(Math.random() * 256) + "," + Math.floor(Math.random() * 256) + "," + Math.floor(Math.random()) + ")";
    var fontSize = Math.floor((Math.random() + 1) * 24) + "px";
    var left = $(".screen_container").width() + "px";
    var top = Math.floor(Math.random() * 400) + "px";
    top = parseInt(top) > 352 ? "352px" : top;
    jqueryDom.css({
        "position": 'absolute',
        "color": fontColor,
        "font-size": fontSize,
        "left": left,
        "top": top
    });
    $(".screen_container").append(jqueryDom);
    return jqueryDom;
}

这里我们需要注意以下几点:

  1. 这里我们是根据定位父级div.screen_container进行定位,这里我们的弹幕值left值都是div.screen_container宽度(即:每个弹幕都从弹幕墙的最右边向左移动)。

  2. 关于弹幕的top值的设定,由于我们字体大小设置在24px~48px之间,保险起见,我们最高top值为352px(即div.screen_container的高度减去48)。

  3. 不要忘记给每个弹幕设置position属性,值为”absolute“

2. 给弹幕加上定时任务。
function addInterval(jqueryDom) {
    var left = jqueryDom.offset().left - $(".screen_container").offset().left;
    var timer = setInterval(function () {
        left--;
        jqueryDom.css("left", left + "px");
        if (jqueryDom.offset().left + jqueryDom.width() < $(".screen_container").offset().left) {
            jqueryDom.remove();
            clearInterval(timer);
        }
    }, 10);
    timers.push(timer);
}

这里我们需要注意以下几点:

  1. 获取指定弹幕的css属性left值,除了上面的方法,还可以通过parseInt(jqueryDom.css("left"))或者parseFloat(jqueryDom.css("left"))获取

  2. 消除弹幕的临界点判断。判断弹幕是否出界,就是看弹幕的最右侧是否出界来判断。这里我们有两种判断方法。第一种,以游览器最左侧作为基准,弹幕距离游览器最左侧的值加上弹幕自身的宽度小于弹幕墙距离游览器最左侧的距离即为出界;第二种:parseFloat(jqueryDom.css("right"))>600判断弹幕的css属性right值是否大于600(即弹幕墙的宽度)。
    3.timers是我们设置的一个全局定时任务队列

3. 监听”发送”按钮
$(".send").on("click", function () {
    // 创建弹幕
    var jqueryDom = createScreenbullet($("#screenBulletText").val());
    // 添加定时任务
    addInterval(jqueryDom);
});

如果我们想体验更好一点,可以加个Enter按钮监听。

$("#screenBulletText").on("keydown", function (event) {
    if (event.keyCode == 13) {
        // 创建弹幕
        var jqueryDom = createScreenbullet($("#screenBulletText").val());
        // 添加定时器
        addInterval(jqueryDom);
    }
});
4. 关闭弹幕功能

第一种:设置弹幕的透明度控制显隐

下面isShow为全局变量,用来记录弹幕的状态。

$(".clear").on("click", function () {
    if (isShow) {
        $(".bullet").css("opacity", 0);
        isShow = false;
    } else {
        $(".bullet").css("opacity", 1);
        isShow = true;
    }
});

这样的好处就是,定时任务不会终结。我们关闭弹幕,实际上是使弹幕不可见。

第二种:直接终结定时任务,并移除所有弹幕

下面timers是我们设置的一个全局定时任务队列。

$(".clear").on("click", function () {
    for(var i=0;i<timers.length;i++){
        clearInterval(timers[i]);
    };
    $(".bullet").remove();
});

这种就是比较简单粗暴了,直接终结了所有定时任务,然后移除了所有弹幕。

以上两种,大家可根据自己的需求去选择。

最终完整版JS代码

// 弹幕定时器
var timers = [];
// 控制弹幕显隐变量
var isShow = true;
// 监听发送按钮
$(".send").on("click", function () {
    // 创建弹幕
    var jqueryDom = createScreenbullet($("#screenBulletText").val());
    // 添加定时任务
    addInterval(jqueryDom);
});
// 监听关闭弹幕按钮
$(".clear").on("click", function () {
    if (isShow) {
        $(".bullet").css("opacity", 0);
        isShow = false;
    } else {
        $(".bullet").css("opacity", 1);
        isShow = true;
    }   
});
// 新建一个弹幕
function createScreenbullet(text) {
    var jqueryDom = $("<div class='bullet'>" + text + "</div>");
    var fontColor = "rgb(" + Math.floor(Math.random() * 256) + "," + Math.floor(Math.random() * 256) + "," + Math.floor(Math.random()) + ")";
    var fontSize = Math.floor((Math.random() + 1) * 24) + "px";
    var left = $(".screen_container").width() + "px";
    var top = Math.floor(Math.random() * 400) + "px";
    top = parseInt(top) > 352 ? "352px" : top;
    jqueryDom.css({
        "position": 'absolute',
        "color": fontColor,
        "font-size": fontSize,
        "left": left,
        "top": top
    });
    $(".screen_container").append(jqueryDom);
    return jqueryDom;
}
// 为弹幕添加定时任务
function addInterval(jqueryDom) {
    var left = jqueryDom.offset().left - $(".screen_container").offset().left;
    var timer = setInterval(function () {
        left--;
        jqueryDom.css("left", left + "px");
        if (jqueryDom.offset().left + jqueryDom.width() < $(".screen_container").offset().left) {
            jqueryDom.remove();
            clearInterval(timer);
        }
    }, 10);
    timers.push(timer);
}

最终效果图

图片描述

快给自己刷波666666吧!


wuming
3.2k 声望788 粉丝

Success is not final, failure is not fatal, it is the courage to continue that counts.