按不同通道加載不同彈幕資料的實作方法
前言
這個需求如題,大體上是将文章的評論資料,在文章的首圖上面以彈幕的形式出現。當時在做這個需求的時候,花了挺多精力的,踩了很多坑,現将彈幕的實作思路寫出來,如果喜歡的話可以點波贊/關注,支援一下,希望大家看完本文可以有所收獲。
實作原理:
實作彈幕的原理,并不算太複雜,耗費一些時間,怼一怼應該都可以做出來。
- 擷取彈幕資料。
- 将彈幕設定為四個通道,每個通道最多隻能出現兩條彈幕。
- 使用
動态設定setInterval
的dom
屬性。left
- 使用dom的
和螢幕的寬度判斷元素是否滾動超出螢幕,然後移除dom。offsetWidth
實作步驟:
1. 首先看一下 html
的結構。
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.擷取彈幕所需要的資料。
要實作彈幕效果肯定需要有資料,這裡就是發請求了。
擷取資料時,要考慮資料量,一次不可能全部都擷取,可以一次擷取一部分,當資料要加載完的時候,再次請求資料。
這裡要記錄資料資料是否全部請求完成,如果請求完成,就可以不再發送資料,直接用之前擷取的全部資料就可以了。
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)
}
}