前端将数据转化为弹幕效果的实现方式

前端将数据转化为弹幕效果的实现方式

前言
这个需求如题,大体上是将文章的评论数据,在文章的首图上面以弹幕的形式出现。当时在做这个需求的时候,花了挺多精力的,踩了很多坑,现将弹幕的实现思路写出来,如果喜欢的话可以点波赞/关注,支持一下,希望大家看完本文可以有所收获。

个人博客了解一下:obkoro1.com

实现效果:

实现原理:
实现弹幕的原理,并不算太复杂,耗费一些时间,怼一怼应该都可以做出来。

获取弹幕数据。
将弹幕设置为四个通道,每个通道最多只能出现两条弹幕。
使用setInterval动态设置dom的left属性。
使用dom的offsetWidth和屏幕的宽度判断元素是否滚动超出屏幕,然后移除dom。
实现步骤:

  1. 首先看一下html的结构。
前端将数据转化为弹幕效果的实现方式

2.获取弹幕所需要的数据。
要实现弹幕效果肯定需要有数据,这里就是发请求了。

获取数据时,要考虑数据量,一次不可能全部都获取,可以一次获取一部分,当数据要加载完的时候,再次请求数据。

这里要记录数据数据是否全部请求完成,如果请求完成,就可以不再发送数据,直接用之前获取的全部数据就可以了。

3.执行弹幕的函数。
弹幕数据获取后,就执行弹幕运行的函数,因为我在写弹幕函数的时候,设置了很多数据状态,这里就大概讲一下实现思路和关键部分代码。

弹幕函数包括的功能:
定时获取数据(判断数据是否加载完毕)
定时发射弹幕(判断通道是否闲置),传入弹幕所需要的内容,用户头像等。
创建dom内容,根据传参生成弹幕div,设置style属性,根据控制弹幕数据数组的下标将div插入对应的dom中。
采用定时器移动dom,这里是根据内容长度定义弹幕的移动速度。
移动弹幕的过程中判断四个通道是否处于闲置状态,当dom移动出了屏幕,移动dom并且清除定时器。

function barrage(){
//第一部分先判断数据是否加载完成 这里是一个定时器,设置为15秒。
//如果数据还未加载完毕,就再次运行请求数据的接口,请求的页数可以 数组/每次请求的条数+1
//数据加载完毕就清除定时器。(我将定时器都保存在vue 组件的data里面) 清除的时候clearInterval(this.data);

//定时发射
 _this.barrageStatus.divStatus.intervalid=setInterval( selfTime,1100);
 function selfTime() { 
    if(_this.dataNum>=_this.barrageStatus.data.length){
    //当dataNum大于等于数组的数量时,弹幕从头再来一遍
      _this.dataNum=0;
    }
//设置四个通道的变量,当这几个变量为false的时候,才可发射
  if(divStatus.div1===false){
    //这里只演示其中一个变量
    divStatus.div1=true;
    _this.dataNum++;                        
   return barrageOut(_this.barrageStatus.data[_this.dataNum-1].content,_this.barrageStatus.data[_this.dataNum-1].commentator.headImgUrl,_this.dataNum);
  }

};

// 创建弹幕内容,自定义弹幕移动速度
function barrageOut(text,imgUrl,num) {
//text:弹幕的内容,imgUrl:用户的头像,num:数组的第几个
if(num%4==1){
//根据数组下标 创建对应通道的节点 这里也演示其中一个
barrageLayer=document.getElementById(‘barrageLayer1’);
}

// 创建dom内容 定义dom style样式
let divBox = document.createElement('div');
let divBoxImg=document.createElement('span');
let divBoxText=document.createElement('span');
divBox.setAttribute('class','barrageDivClass');
divBoxText.innerHTML=text;
divBox.appendChild(divBoxImg);
divBoxImg.setAttribute('class','barrageDivClass_img');
divBoxImg.style.backgroundImage=`url(${imgUrl})`;
divBox.appendChild(divBoxText);
divBox.style.left=document.body.clientWidth+2000+'px';// 初始化left位置,一开始在屏幕的右侧
barrageLayer.appendChild(divBox);

// 定时器移动dom,形成弹幕
let time,l=0;
time= setInterval(function(){
  if(text.length<15){ 
  // 这里可以根据需求自定义弹幕加载的速度
    l=l-1;
  }else{
    l=l-2;
  }

  //通过减少left属性移动这个div 从右往左移动
 divBox.style.left = document.body.clientWidth+l+'px';
  let delDiv=()=>{
        if(num%4==1){ 
         //在移动弹幕的过程中判断四个通道是否处于闲置状态 这里只演示其中一个
          barrageLayer=document.getElementById('barrageLayer1');
          if(barrageLayer.childNodes.length<2){
            //判断弹幕数量,如果小于2,设为false,上面的定时器可以继续发射弹幕
            divStatus.div1=false;
          }else{
            divStatus.div1=true;
          }
      }
    }
  }
  if( l <= (0-divBox.offsetWidth-120) ){ 
    if(_this.barrageStatus.divStatus.switch==true){ //弹幕开关
      delDiv();
      if(l <= (0-divBox.offsetWidth-document.body.clientWidth) ){
        //不断减少left属性,当小于这个内容的宽度,并且滚了120的时候
          barrageLayer.removeChild(divBox); //移除dom
          clearInterval(time);//清除这个div的定时器
        }
    }else{
       clearInterval(time);//清除这个div的定时器
    }
  }
},20)

}
}
结语
这个弹幕需求,我是如上这么实现的,回头看看实现,发现还是有不少地方可以优化和拆分的,如果有更好的实现思路和本文有哪些错误,欢迎在评论区下面留言。

前端将数据转化为弹幕效果的实现方式

原文链接

http://obkoro1.com/2018/04/30/%E5%89%8D%E7%AB%AF%E5%B0%86%E6%95%B0%E6%8D%AE%E8%BD%AC%E5%8C%96%E4%B8%BA%E5%BC%B9%E5%B9%95%E6%95%88%E6%9E%9C%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F/

服务推荐