vue 直播彈幕功能

需求是不重疊彈幕
公司使用的是云信接發(fā)消息,我的思路是給直播間四條彈幕跑道,接收到彈幕之后往跑道內(nèi)插入彈幕
以下是其中一條彈幕跑道的html:

        <div class="trumpet-box box1" v-for="(item,index) in list[0]">
                <div class="trumpet-item">
                    <div class="top">
                        <i v-show="item.barrageType === 64"></i>
                        <span v-show="item.grade>5"></span>
                        <p>{{item.userNickname}}</p>
                    </div>
                    <div class="bottom">
                        <img :src="item.userAvatar">
                        <p>{{item.content}}</p>
                        <i v-show="item.barrageType === 64"></i>
                    </div>
                </div>
        </div>

trumpet-item 為彈幕 如果接收到消息就往list里push,push前先判斷當(dāng)前跑道能不能插入彈幕,確保當(dāng)前彈幕不會(huì)和上一條彈幕重疊,如果不能(即當(dāng)前跑道有一條彈幕正在移動(dòng)),則把當(dāng)前彈幕插入下一條彈幕跑道里(我這里一共設(shè)了四條跑道),下面是方法:
注:我這邊定義的是彈幕在屏幕上移動(dòng)的時(shí)長(zhǎng)是6s,彈幕移動(dòng)動(dòng)畫用的是translate
首先是先把從云信接收的消息體obj整理成自己想要的格式

        formatObj(obj){
            let width = this.textSize(14,obj.content)>70?this.textSize(14,obj.content)+70:140//元素的寬度
            let boxWidth = document.getElementsByClassName('center')[0].offsetWidth //屏幕寬度
            let speed = (width+boxWidth)/6   //彈幕速度
            obj.second = (width/speed).toFixed(1)*1000 //元素插入需要的時(shí)間
            obj.startTime =  Date.now() //元素動(dòng)畫開始的時(shí)間
            obj.endTime =  obj.startTime+6000+obj.second //元素動(dòng)畫結(jié)束的時(shí)間
            obj.trumpetItemShow = true
            let style = document.styleSheets[0];
            let transformWidth = width+boxWidth;
            transformWidth = (Math.ceil(transformWidth))%2 ==0 ? Math.ceil(transformWidth) :Math.ceil(transformWidth)+1 //防止字體模糊
            style.insertRule("@keyframes bounce-in{from{ transform: translateX(0); }to{ transform: translateX(-"+transformWidth+"px);}}",1);//寫入樣式
            return obj
        },
        textSize(fontSize, text) { //根據(jù)文本內(nèi)容獲取元素寬度
            let span = document.createElement("span");
            span.innerText = text
            span.style.visibility = "hidden";
            span.style.fontSize = fontSize+'px';
            span.style.id = 'fakeSpan';
            document.getElementsByClassName("center")[0].appendChild(span);
            let newWidth = span.offsetWidth;
            document.getElementsByClassName("center")[0].removeChild(span);
            return newWidth;
        }

上面的方法的作用是
計(jì)算出并記錄下
1.彈幕從屏幕左邊出現(xiàn)到完全出現(xiàn)需要的時(shí)間
2.彈幕插入動(dòng)畫開始的時(shí)間(在屏幕左邊出現(xiàn)前一秒)
3彈幕動(dòng)畫結(jié)束的時(shí)間(在屏幕右邊消失的后一秒)
用于判斷↓

 //判斷當(dāng)前彈幕是否能插入跑道
        getTrack(val){   //val是格式化好的彈幕
            let obj =  _.cloneDeep(val)
            for(let i = 0;i<this.list.length;i++){ //遍歷四條跑道
                let lastChatData = this.list[i][this.list[i].length-1]  //當(dāng)前跑道最后一條數(shù)據(jù)
                if(this.list[i].length==0){  //如果是當(dāng)前跑道的第一條數(shù)據(jù) 直接插入跑道
                    this.list[i].push(this.formatObj(obj))
                    return
                }
                if(Date.now()-lastChatData.startTime>lastChatData.second){  //如果不是當(dāng)前跑道的第一條數(shù)據(jù) 過了等待時(shí)間插入跑道
                    this.list[i].push(this.formatObj(obj))
                    return
                } 
            }
            //都不是則進(jìn)入等待隊(duì)列
            this.toWait.push(obj)   
        },

this.toWait 是等待隊(duì)列 ,在所有跑道都有彈幕在插入的時(shí)候,新的彈幕消息進(jìn)入等待隊(duì)列,然后定時(shí)詢問是否有跑道能插入數(shù)據(jù) ,我這里使用的是watch

    watch:{
        YxLiveRoomBarrageVo(val){ //接收到消息的時(shí)候判斷是否能插入彈幕
            this.getTrack(val)
        },
        toWait(newVal){ //等待隊(duì)列有值得時(shí)候定時(shí)詢問是否能插入彈幕
            if(newVal.length>0){
                this.timer = setInterval(()=>{
                    for(let item of newVal){
                        this.getTrack(item)
                        this.toWait.shift()
                    }
                }, 500)
            }else{
                this.timer && clearInterval(this.timer)
            }
        },
        list(newVal){
            this.list.forEach((val,index)=>{
                if(val.length>=20){
                    this.delectItem(val)
                }
            })
        }
    },

list是我的四條跑道

data(){
        return {
            list:[[],[],[],[]],
            timer:null,
            timer1:null,
            toWait:[] //等待插入的彈幕
        }
    },

監(jiān)聽它是為了定時(shí)清理數(shù)據(jù) ,每條跑道的彈幕數(shù)據(jù)大于20的時(shí)候清理一次,
清理的方法是

        delectItem(arr){ //定時(shí)清除
            for(let i = 0;i<arr.length;i++){
                if(arr[i].endTime<Date.now()){
                    arr[i].trumpetItemShow = false
                }
            }
        },

所以上面的endTime是用來判斷但是是不是已經(jīng)完成動(dòng)畫了,完成了的彈幕就能清理掉,最后

    destroyed() {
        this.timer && clearInterval(this.timer)
        this.timer1 && clearInterval(this.timer1)
    }

清一下定時(shí)器


成果.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 版本記錄 前言 在我們做直播等視頻類app的時(shí)候,總是有顯示和發(fā)送彈幕的要求,彈幕可以方便用戶進(jìn)行溝通和互動(dòng),增加...
    刀客傳奇閱讀 5,473評(píng)論 8 16
  • 重點(diǎn)參考鏈接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi閱讀 4,701評(píng)論 0 15
  • 那一夜,她依偎在我懷里,問我,你有什么理想。 我以為云雨過后的女生都會(huì)問,你愛我么?這種傻逼問題,愣是沒想到她竟然...
    乄清玄閱讀 343評(píng)論 0 0
  • 鬧鐘定了6個(gè),其實(shí)第一個(gè)開始響的時(shí)候我就已經(jīng)醒了,醒來第一件事先是打開手機(jī)刺激眼部神經(jīng),翻看微信和其他軟件的消息,...
    鉞冥閱讀 710評(píng)論 0 4
  • 三月,早櫻已經(jīng)盛開 你走在河邊上,欣賞春光 一棵柳樹垂下萬千柳條 靜靜的發(fā)芽 河里有一條藍(lán)色的船 在水中蕩來蕩去 ...
    葉落心閱讀 276評(píng)論 0 2

友情鏈接更多精彩內(nèi)容