网站首页 » 前端开发 » JavaScript » JavaScript 视频文字弹幕效果
上一篇:
下一篇:

JavaScript 视频文字弹幕效果

前言

视频弹幕效果到处都是,这种交互大大地改变了网友之间的交流方式 ,让你看视频的时候,可以发评论,可以看到别人的评论,真是一石三鸟。用户体验没得说,所以本文就是将要分享这个效果。上码!

各种套路

套路一

简单的 CSS 样式如下 :

样式看这里
*{
    padding: 0;
    margin: 0;
}
html,body{
    width: 100%;
    height: 100%;
    overflow: hidden;
}
  .stage{
    position: relative;
    width: 100%;
    height: 100%;
    border: 1px solid #ccc;
    overflow:hidden;
    background: #000;
    color: #fff;
}
.stage .player{
    position: absolute;
    font-size: 0.35rem;
    white-space: nowrap;
}

HTML 代码也非常地简单明了:

HTML 代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript 视频文字弹幕效果 - 云库前端</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
</head>
<body>
<div class="stage" id="stage"></div>
<script src="http://yunkus.com/demo/lib/js/dynamics.min.js"></script>
<script src="js/index.js"></script>
<script>
var ele = document.getElementById("stage");
var arr = ["HTML5 快跑","JavaScript 也有一遍天","CSS 教程,真的很贴心","NODE 之光,所到之处,都亮瞎了万物","jQuery 教程","Angular 是什么","ionic 来自何方","前端开发有没有前景","SEO 教程算个啥","VUE 就是轻","Express 教程","前端动画库","JavaScript 基础","JavaScript 大神求带","JavaScript 从入门到放弃","JavaScript 还有未来吗?","CSS3 炫得不要不要的","JavaScript 就是6","Canvas 教程","Canvas 动画美得......","前端小白一枚","前端是一个大坑","做一个有梦的人","前端路长且艰","一山不有一山高","程序员也打球","不要以为你是一个程序员就没有女朋友","如果世界没有程序员","前端自适应头都大了","做一个有情趣的程序员","小猪快跑"];
/*
 * stage 元素
 * data 文字数组
 * actorNumber:一屏显示多少个
 * duration 走完一屏的时长范围(速度)
 * delay 延迟的范围
 */
var stagePlayer = new stagePlayer({
  stage:ele,
  data:arr,
  actorNumber:8,
  duration:{start:6000,end:12000},
  delay:{start:1000,end:2000}
});
</script>
</body>
</html>

下面就是实现这个效果的关键 JavaScript 千万不能眨眼:

JavaScript 代码
/*
* @Author: 朝夕熊
* @Date:   2017-11-14 21:12:37
* @Last Modified by:   朝夕熊
* @Last Modified time: 2017-11-14 22:19:56
*/

// 设置基准值
(function(){
    var html = document.documentElement;
    var htmlW = html.getBoundingClientRect().width;
    var fontSize = htmlW/7.5;
    html.style.fontSize = fontSize+"px";
})();

function stagePlayer(setting){
    sThis = this;
    sThis.arr = setting.data || [];
    sThis.totleLength = sThis.arr.length; // 总文字条数
    sThis.actorNumber = setting.actorNumber || 12;
    sThis.stage = setting.stage;
    sThis.stageW = sThis.stage.offsetWidth;
    sThis.stageH = sThis.stage.offsetHeight;
    sThis.durationStart = setting.duration.start || 3000;
    sThis.durationEnd = setting.duration.end || 10000;
    sThis.delayStart = setting.delay.start || 100;
    sThis.delayEnd = setting.delay.end || 5000;
    sThis.index = 0;
    sThis.actorContainer = [];
    sThis.actorHeight = 0;
    sThis.init();
}

window.onresize = function(){
    sThis.resize();
}

// 初始化
stagePlayer.prototype.init = function(){
    sThis.createActor();
    sThis.initPosition();
}

stagePlayer.prototype.resize = function(){
    sThis.stageW = sThis.stage.offsetWidth;
    sThis.stageH = sThis.stage.offsetHeight;
    sThis.initPosition();
}

// 生成条数
stagePlayer.prototype.createActor = function(){
    for(var i=0;i<sThis.actorNumber;i++){
        var ele = document.createElement("div");
        ele.innerText = sThis.arr[i];
        ele.className = "player";
        ele.id = "player" + i;
        document.body.appendChild(ele);
        sThis.index = i;
        sThis.actorContainer.push(ele);
        sThis.stage.appendChild(ele);
    }
    sThis.actorHeight = sThis.actorContainer[0].offsetHeight;
}

// 初始化(第一次打开)
stagePlayer.prototype.initPosition = function(){
    for(var i=0;i<sThis.actorNumber;i++){
        sThis.createPosition(sThis.actorContainer[i]);
        sThis.actorContainer[i].delay = 0;
        sThis.initAnimateActor(sThis.actorContainer[i]);
    }
}

// 初始化(第一次打开)
stagePlayer.prototype.initAnimateActor = function(actor){
    sThis.animateActor(actor);
}

// 创建文字的位置及随机生成相关参数
stagePlayer.prototype.createPosition = function(actor){
    actor.startY = getRandom(0,sThis.stageH);
    actor.startX = actor.offsetWidth;
    sThis.updateCurrentActorTargeX(actor);
    if(actor.startY > sThis.stageH - sThis.actorHeight){
        actor.startY = sThis.stageH - sThis.actorHeight + "px";
    }
    actor.style.left = sThis.stageW + "px";
    actor.style.top = actor.startY + "px";
    actor.duration = getRandom(sThis.durationStart,sThis.durationEnd);
    actor.delay = getRandom(sThis.delayStart,sThis.delayEnd);
}

// 开始动画
stagePlayer.prototype.animateActor = function(actor){
    sThis.updateCurrentActorTargeX(actor);
    dynamics.animate(actor,{
        left:(actor.targeX)
    },{
        type:dynamics.easeIn,
        duration:actor.duration,
        delay:actor.delay,
        complete:sThis.changeActor
    });
}

// 改变 Actor 的开始|目标位置
stagePlayer.prototype.changeActor = function(){
    for(var i=0;i<sThis.actorNumber;i++){
        if(sThis.actorContainer[i].offsetLeft <= sThis.actorContainer[i].targeX){
            sThis.index+=1;
            if(sThis.index == sThis.totleLength){
                sThis.index = 0;
            }
            sThis.actorContainer[i].innerText = sThis.arr[sThis.index];
            sThis.createPosition(sThis.actorContainer[i]);
            sThis.updateCurrentActorTargeX(sThis.actorContainer[i]);
            sThis.animateActor(sThis.actorContainer[i]);
            return;
        }
    }
}

// 更新当前元素开始位置
stagePlayer.prototype.updateCurrentActorTargeX = function(actor){
    actor.targeX = -actor.offsetWidth;
}

// 生成随机数
function getRandom(min,max){
    return parseInt(Math.random()*(max-min)+min);
}

把代码贴出来估计就意味着本文快到尾声了。看再多也不如看个在线 DEMO:http://yunkus.com/demo/javascript-vedio-barrage/

可以设置多个参数,具体用法可以看代码里的注解。

这个效果的大体思路:

  • 为这出戏搭个场子(stage)。
  • 根据用户设置的个数生成等量的 div 元素(过场演员)。
  • 把用户预设的数据依次填到固定数量的 div 元素中。
  • 如果有元素运动超出了可视区,那么就从用户给定的数据中拿下一条来更新这个元素的文字。再把这个元素重置下,像一开始那么。
  • 如此往返,如果用户数据遍历完,那么程序就会从数据的第一个开始取,一直循环下去,直到永远。

本例子中用到了dynamics.js 库,里的一个运动函数,来实现文字的过场效果,仅此而已,你也可以自己写一个动画方法来完成文字的过场效果。

套路二

到这里本文就已经接近尾声了。但我们不条条道路通罗马,除了通过绝对定位的方式来实现文字的漂流效果,我们还可以通过 CSS3 的 translate 来实现,代码如下:

HTML 代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <meta content="telephone=no" name="format-detection" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="default" />
    <title>JavaScript 视频文字弹幕效果加强版 - 云库前端</title>
    <style>
        *{
          padding: 0;
          margin: 0;
        }
        html,body{
          width: 100%;
          height: 100%;
          overflow: hidden;
        }
          .stage{
            position: relative;
            width: 100%;
            height: 100%;
            border: 1px solid #ccc;
            overflow:hidden;
            background: #000;
            color: #fff;
        }
        .stage .player{
          position: absolute;
          font-size: 0.35rem;
          white-space: nowrap;
        }
    </style>
</head>
<body>
<div class="stage" id="stage"></div>
<script src="http://yunkus.com/demo/lib/js/dynamics.min.js"></script>
<script src="js/index2.js"></script>
<script>
   var ele = document.getElementById("stage");
   var arr = ["HTML5 快跑","JavaScript 也有一遍天","CSS 教程,真的很贴心","NODE 之光,所到之处,都亮瞎了万物","jQuery 教程","Angular 是什么","ionic 来自何方","前端开发有没有前景","SEO 教程算个啥","VUE 就是轻","Express 教程","前端动画库","JavaScript 基础","JavaScript 大神求带","JavaScript 从入门到放弃","JavaScript 还有未来吗?","CSS3 炫得不要不要的","JavaScript 就是6","Canvas 教程","Canvas 动画美得......","前端小白一枚","前端是一个大坑","做一个有梦的人","前端路长且艰","一山不有一山高","程序员也打球","不要以为你是一个程序员就没有女朋友","如果世界没有程序员","前端自适应头都大了","做一个有情趣的程序员","小猪快跑"];
        /*
         * stage 元素
         * data 文字数组
         * actorNumber:一屏显示多少个
         * duration 走完一屏的时长范围(速度)
         * delay 延迟的范围
         */
        var stagePlayer = new StagePlayer({
          stage:ele,
          data:arr,
          actorNumber:8,
          duration:{start:5000,end:10000},
          delay:{start:1000,end:3000}
        });
</script>
</body>
</html>

html 代码跟上面的基本没什么变化。

JavaScript 代码
/*
* @Author: 朝夕熊
* @Date:   2017-10-23 13:40:18
* @Last Modified by:   朝夕熊
* @Last Modified time: 2017-11-29 00:09:25
*/

(function(){
	var html = document.documentElement;
	var htmlW = html.getBoundingClientRect().width;
	var fontSize = htmlW/7.5;
	html.style.fontSize = fontSize+"px";
})();

var sThis = null;
function StagePlayer(setting) {
    sThis = this;
    sThis.arr = setting.data || [];
    sThis.totleLength = sThis.arr.length; // 总文字条数
    sThis.actorNumber = setting.actorNumber || 12;
    sThis.stage = setting.stage;
    sThis.stageW = sThis.stage.offsetWidth;
    sThis.stageH = sThis.stage.offsetHeight;
    sThis.durationStart = setting.duration.start || 3000;
    sThis.durationEnd = setting.duration.end || 10000;
    sThis.delayStart = setting.delay.start || 100;
    sThis.delayEnd = setting.delay.end || 5000;
    sThis.index = 0;
    sThis.actorContainer = [];
    sThis.actorHeight = 0;
    sThis.init();
}

window.onresize = function () {
    sThis.resize();
}

StagePlayer.prototype.resize = function () {
    sThis.stageW = sThis.stage.offsetWidth;
    sThis.stageH = sThis.stage.offsetHeight;
   // 如果还没运动的元素就重置初始位置 startX
   for(var i=0;i<sThis.actorNumber;i++){
        var flag = getTranslate(sThis.actorContainer[i].style.transform);
        if(flag){
            sThis.actorContainer[i].startX = sThis.stageW;
            sThis.actorContainer[i].style.transform = sThis.actorContainer[i].style.WebkitTransform = "translate("+ sThis.actorContainer[i].startX +"px,"+ sThis.actorContainer[i].startY +"px)";
        }
   }

}

StagePlayer.prototype.init = function(){
    sThis.createActor();
}

StagePlayer.prototype.createActor = function(){
    for(var i=0;i<sThis.actorNumber;i++){
        var ele = document.createElement("div");
        ele.innerText = sThis.arr[i];
        ele.className = "player";
        ele.id = "player" + i;
        document.body.appendChild(ele);
        sThis.index = i;
        sThis.actorContainer.push(ele);
        sThis.stage.appendChild(ele);
    }
    sThis.actorHeight = sThis.actorContainer[0].offsetHeight;

    sThis.initPosition();
}

// 初始化(第一次打开)
StagePlayer.prototype.initPosition = function(){
    for(var i=0;i<sThis.actorNumber;i++){
        sThis.createPosition(sThis.actorContainer[i]);
        sThis.actorContainer[i].delay = getRandom(10,30);
        sThis.animateActor(sThis.actorContainer[i]);
    }
}

// 创建文字的位置及随机生成相关参数
StagePlayer.prototype.createPosition = function(actor){
    sThis.updateActorPosition(actor);
    actor.duration = getRandom(sThis.durationStart,sThis.durationEnd);
    actor.delay = getRandom(sThis.delayStart,sThis.delayEnd);
}

// 改变 Actor 的开始|目标位置
StagePlayer.prototype.changeActor = function(){
    for(var i=0;i<sThis.actorNumber;i++){
        var tx = getMartri3d(sThis.actorContainer[i].style.transform)[12];
        if(tx <= sThis.actorContainer[i].targeX){
            sThis.index+=1;
            if(sThis.index == sThis.totleLength){
                sThis.index = 0;
            }
            sThis.actorContainer[i].innerText = sThis.arr[sThis.index];
            sThis.createPosition(sThis.actorContainer[i]);
            sThis.animateActor(sThis.actorContainer[i]);
            return;
        }
    }
}

// 获取矩阵中的 translateX 的值
function getMartri3d(mt){
    var temp = "";
    var pat = /^(matrix3d\()(.*)(\))/g;
    mt.replace(pat,function($0,$1,$2){
        temp = $2.replace(/\s/g,"");
        temp = temp.split(",");
        for(var i=0;i<temp.length;i++){
            temp[i] = parseInt(temp[i]);
        }
    });
    return temp;
}

// 通过正则简单匹配,判断元素是否已经开始运动。true 为未开始运动,false 为已经开始运动
function getTranslate(tl){
    var temp = "";
    var pat = /px/g;
    temp = pat.test (tl);
    return temp;
}

// 开始动画
StagePlayer.prototype.animateActor = function(actor){
    dynamics.animate(actor,{
        translateX:actor.targeX,
        translateY:actor.targeY
    },{
        type:dynamics.easeIn,
        duration:actor.duration,
        delay:actor.delay,
        complete:sThis.changeActor
    });
}

StagePlayer.prototype.updateActorPosition = function(actor){
    actor.startX = sThis.stageW;
    actor.startY = getRandom(0,sThis.stageH);
    if(actor.startY > sThis.stageH - sThis.actorHeight){
        actor.startY = sThis.stageH - sThis.actorHeight;
    }
    actor.targeX = -actor.offsetWidth;
    actor.targeY = actor.startY;
    actor.style.transform = actor.style.WebkitTransform = "translate("+ actor.startX +"px,"+ actor.startY +"px)";
    sThis.resizeFlag = false;
}

function getRandom(min,max){
    return parseInt(Math.random()*(max-min)+min);
}

在线DEMO:http://yunkus.com/demo/javascript-vedio-barrage/index2.html,请用手机查看效果,至此本文就已经完美收场了,发挥你的想像力,创造更多吧。

 

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/javascript-vedio-barrage/

Leave a Reply

Your email address will not be published. Required fields are marked *

评论 END