前端將數據轉化為彈幕效果的實現方式


前言

這個需求如題,大體上是將文章的評論數據,在文章的首圖上面以彈幕的形式出現。當時在做這個需求的時候,花了挺多精力的,踩了很多坑,現將彈幕的實現思路寫出來,如果喜歡的話可以點波贊/關注,支持一下,希望大家看完本文可以有所收獲。

 

實現效果:

 

實現原理:

實現彈幕的原理,並不算太復雜,耗費一些時間,懟一懟應該都可以做出來。

  1. 獲取彈幕數據。
  2. 將彈幕設置為四個通道,每個通道最多只能出現兩條彈幕。
  3. 使用setInterval動態設置dom的left屬性。
  4. 使用dom的offsetWidth和屏幕的寬度判斷元素是否滾動超出屏幕,然后移除dom

資源網站大全 https://55wd.com 設計導航https://www.wode007.com/favorites/sjdh

實現步驟:

1. 首先看一下html的結構。

<div>
    <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.獲取彈幕所需要的數據。

要實現彈幕效果肯定需要有數據,這里就是發請求了。

獲取數據時,要考慮數據量,一次不可能全部都獲取,可以一次獲取一部分,當數據要加載完的時候,再次請求數據。

這里要記錄數據數據是否全部請求完成,如果請求完成,就可以不再發送數據,直接用之前獲取的全部數據就可以了。

3.執行彈幕的函數。

彈幕數據獲取后,就執行彈幕運行的函數,因為我在寫彈幕函數的時候,設置了很多數據狀態,這里就大概講一下實現思路和關鍵部分代碼。

彈幕函數包括的功能:

  1. 定時獲取數據(判斷數據是否加載完畢)
  2. 定時發射彈幕(判斷通道是否閑置),傳入彈幕所需要的內容,用戶頭像等。
  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)
  }
}

  

 

結語

這個彈幕需求,我是如上這么實現的,回頭看看實現,發現還是有不少地方可以優化和拆分的,如果有更好的實現思路和本文有哪些錯誤,歡迎在評論區下面留言。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM