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

前言

这个需求如题,大致上是将文章的评论数据,在文章的首图上面以弹幕的形式出现。当时在作这个需求的时候,花了挺多精力的,踩了不少坑,现将弹幕的实现思路写出来,若是喜欢的话能够点波赞/关注,支持一下,但愿你们看完本文能够有所收获。css

我的博客了解一下:obkoro1.comhtml


实现效果:

实现原理:

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

  1. 获取弹幕数据。
  2. 将弹幕设置为四个通道,每一个通道最多只能出现两条弹幕。
  3. 使用setInterval动态设置domleft属性。
  4. 使用dom的offsetWidth和屏幕的宽度判断元素是否滚动超出屏幕,而后移除dom。

实现步骤:

1. 首先看一下html的结构。

<div class="detailImg">
        <img src="url"/>
        <div id="barrageDiv">
            <div id="barrageLayer1"></div>
            <div id="barrageLayer2"></div>
            <div id="barrageLayer3"></div>
            <div id="barrageLayer4"></div>
        </div>
      </div>
      <!--detailImg 设置relative, barrageDiv设置z-index在图片上面,以及图片的位置-->
      <!---barrageLayer1~4 主要设置了一个top属性让四个div在各自的水平线上,造成四个通道->
复制代码

关于这里的css样式,关键点都在上面说了,就注意一下上面通道是怎样造成的,就能够了。具体的样式也就不贴出来了,就根据各自的需求来吧。数组

2.获取弹幕所须要的数据。

要实现弹幕效果确定须要有数据,这里就是发请求了。app

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

这里要记录数据数据是否所有请求完成,若是请求完成,就能够再也不发送数据,直接用以前获取的所有数据就能够了。函数

3.执行弹幕的函数。

弹幕数据获取后,就执行弹幕运行的函数,由于我在写弹幕函数的时候,设置了不少数据状态,这里就大概讲一下实现思路和关键部分代码。学习

弹幕函数包括的功能:

  1. 定时获取数据(判断数据是否加载完毕)优化

  2. 定时发射弹幕(判断通道是否闲置),传入弹幕所须要的内容,用户头像等。this

  3. 建立dom内容,根据传参生成弹幕div,设置style属性,根据控制弹幕数据数组的下标将div插入对应的dom中。

  4. 采用定时器移动dom,这里是根据内容长度定义弹幕的移动速度。

  5. 移动弹幕的过程当中判断四个通道是否处于闲置状态,当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)
       }
     }
    复制代码

结语

这个弹幕需求,我是如上这么实现的,回头看看实现,发现仍是有很多地方能够优化和拆分的,若是有更好的实现思路和本文有哪些错误,欢迎在评论区下面留言。

但愿看完的朋友能够点个喜欢/关注,您的支持是对我最大的鼓励。

最后:如需转载,请放上原文连接并署名。码字不易,感谢支持!本人写文章本着交流记录的心态,写的很差之处,不撕逼,可是欢迎指点。

我的blog and 掘金我的主页

关注个人订阅号,来一块儿学习成长。

以上2018.4.29

参考资料:

纯js 实现弹幕效果

相关文章
相关标签/搜索