這個需求如題,大致上是將文章的評論數據,在文章的首圖上面以彈幕的形式出現。當時在作這個需求的時候,花了挺多精力的,踩了不少坑,現將彈幕的實現思路寫出來,若是喜歡的話能夠點波贊/關注,支持一下,但願你們看完本文能夠有所收穫。css
我的博客瞭解一下:obkoro1.comhtml
實現彈幕的原理,並不算太複雜,耗費一些時間,懟一懟應該均可以作出來。vue
setInterval
動態設置dom
的left
屬性。offsetWidth
和屏幕的寬度判斷元素是否滾動超出屏幕,而後移除dom。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樣式,關鍵點都在上面說了,就注意一下上面通道是怎樣造成的,就能夠了。具體的樣式也就不貼出來了,就根據各自的需求來吧。數組
要實現彈幕效果確定須要有數據,這裏就是發請求了。markdown
獲取數據時,要考慮數據量,一次不可能所有都獲取,能夠一次獲取一部分,當數據要加載完的時候,再次請求數據。app
這裏要記錄數據數據是否所有請求完成,若是請求完成,就能夠再也不發送數據,直接用以前獲取的所有數據就能夠了。dom
彈幕數據獲取後,就執行彈幕運行的函數,由於我在寫彈幕函數的時候,設置了不少數據狀態,這裏就大概講一下實現思路和關鍵部分代碼。函數
定時獲取數據(判斷數據是否加載完畢)oop
定時發射彈幕(判斷通道是否閒置),傳入彈幕所須要的內容,用戶頭像等。學習
建立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)
}
}
複製代碼
這個彈幕需求,我是如上這麼實現的,回頭看看實現,發現仍是有很多地方能夠優化和拆分的,若是有更好的實現思路和本文有哪些錯誤,歡迎在評論區下面留言。
最後:如需轉載,請放上原文連接並署名。碼字不易,感謝支持!本人寫文章本着交流記錄的心態,寫的很差之處,不撕逼,可是歡迎指點。
關注個人訂閱號,來一塊兒學習成長。
以上2018.4.29