前言
這個需求如題,大體上是將文章的評論資料,在文章的首圖上面以彈幕的形式出現。當時在做這個需求的時候,花了挺多精力的,踩了很多坑,現將彈幕的實現思路寫出來,如果喜歡的話可以點波贊/關注,支援一下,希望大家看完本文可以有所收穫。
個人部落格瞭解一下:obkoro1.com
實現效果:
實現原理:
實現彈幕的原理,並不算太複雜,耗費一些時間,懟一懟應該都可以做出來。
- 獲取彈幕資料。
- 將彈幕設定為四個通道,每個通道最多隻能出現兩條彈幕。
- 使用
setInterval
動態設定dom
的left
屬性。 - 使用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.獲取彈幕所需要的資料。
要實現彈幕效果肯定需要有資料,這裡就是發請求了。
獲取資料時,要考慮資料量,一次不可能全部都獲取,可以一次獲取一部分,當資料要載入完的時候,再次請求資料。
這裡要記錄資料資料是否全部請求完成,如果請求完成,就可以不再傳送資料,直接用之前獲取的全部資料就可以了。
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) } } 複製程式碼
結語
這個彈幕需求,我是如上這麼實現的,回頭看看實現,發現還是有不少地方可以優化和拆分的,如果有更好的實現思路和本文有哪些錯誤,歡迎在評論區下面留言。
希望看完的朋友可以點個喜歡/關注,您的支援是對我最大的鼓勵。
最後:如需轉載,請放上原文連結並署名。碼字不易,感謝支援!本人寫文章本著交流記錄的心態,寫的不好之處,不撕逼,但是歡迎指點。
關注我的訂閱號,來一起學習成長。
以上2018.4.29