使用canvas實現(xiàn)一個vue彈幕組件功能
看B站時,對彈幕的實現(xiàn)產(chǎn)生了興趣,一開始想到用css3動畫去實現(xiàn),后來感覺這樣性能不是很好,查了下資料,發(fā)現(xiàn)可以用canvas實現(xiàn),于是就摸索著寫了一個簡單的彈幕。
彈幕功能
- 支持動態(tài)添加彈幕
- 彈幕不重疊
- 自定義彈幕顏色
效果圖
前端框架選了比較熟悉的vuejs
彈幕滾動的基本思路就是通過定時器不斷地改變彈幕的位置,時時重繪畫布。
實現(xiàn)步驟
先加入一個canvas標(biāo)簽,這里有個注意點,關(guān)于設(shè)備像素比對canvas的影響,會出現(xiàn)繪圖模糊。
<canvas width="600" height="600"></canvas> // 如果單純這樣寫,canvas會出現(xiàn)模糊 <canvas width="600" height="600" style="width: 300px;height: 300px"> </canvas> //為了不出現(xiàn)模糊,需要設(shè)置canvas的css寬高為上下文寬高的1/devicePixelRatio, 本文是對于devicePixelRatio:2的設(shè)備設(shè)置的,該值可從window.devicePixelRatio取得。 <canvas ref="hiddenCanvas" width="0" height="0" style="display: none"> </canvas> // 后面會用到
我們先定義一個數(shù)組來存放彈幕數(shù)據(jù),一條彈幕信息,包括文本內(nèi)容,x,y坐標(biāo)位置,顏色,速度(可以是隨機或者固定,為了計算簡單,我們這里采用了固定的速度)
var dmArr = []; var gap = 80; // 彈幕的上下間距 var hiddenCanvas = this.$refs.hiddenCanvas; // 增加彈幕的方法 function pushDm(text, color) { let y = getY(); // 先確定跑道 let x = 600; // 初始x坐標(biāo)為canvas的右邊界 let delayWidth = 0; // 同跑道 for (let i = 0, len = dmArr.length; i < len; i++) { let dm = dmArr[i]; if (y === dm.y) { // 如果是同跑道,則往后排,設(shè)置一定的間隔,保證彈幕不會重疊; delayWidth += Math.floor(hiddenCanvas.getContext('2d').measureText(dm.text).width * 4 + 50); } } dmArr.push({ text: text, x: x + delayWidth, y: y, speed: 8, color: color || getColor() }); } // 隨機獲得y坐標(biāo) function getY() { let range = Math.floor(600 / gap); // 跑道數(shù)量 return Math.floor(Math.random() * range + 1) * gap; } // 隨機獲得顏色 function getColor() { return `${Math.floor(Math.random() * 16777215).toString(16)}`; } // 寫一個for循環(huán),初始化30條彈幕 for (let i = 0; i < 30; i++) { pushDm(`It's barrage ${i}`); }
接下來設(shè)置一個20ms的定時器,實現(xiàn)彈幕滾動效果
var timer = null; var ctx = this.$refs.canvas.getContext('2d'); function start(){ timer = setInterval(() => { ctx.clearRect(0, 0, 600, 600); // 每次需要清空畫布 ctx.save(); ctx.font = '30px Microsoft YaHei'; // 這里需要把字體大小設(shè)為需要顯示的css大小的2倍(devicePixelRatio為2時) if (!dmArr.length) stop(); // 如果沒有新彈幕了,就停止計時器 for (let i = 0, len = this.dmArr.length; i < len; i++) { let dm = dmArr[i]; let overRange = -ctx.measureText(dm.text).width * 2; dm.x -= dm.speed; if (dm.x < overRange) { dmArr.splice(i, 1); // 彈幕在畫布中不可見時,從數(shù)組中移除該項 continue; } ctx.fillStyle = `#${dm.color}`; ctx.fillText(dm.text, dm.x, dm.y); } ctx.restore(); }, 20); } function stop() { clearInterval(timer); ctx.clearRect(0, 0, 600, 600); }
我們還需要一個輸入框,來實現(xiàn)手動添加彈幕功能
<input type="text" @keyup.enter="sent" v-model="dmInput" maxlength="20"> <button type="button" @click="sent">發(fā)表</button> var dmInput = ''; var color = ''; // 可自定義彈幕的顏色 function sent() { if (!dmInput) return; stop(); pushDm(dmInput, color); start(); dmInput = ''; }
有待改進的地方和疑問?速度不恒定時,怎么保持彈幕不重疊視頻彈幕是根據(jù)彈幕發(fā)送時間點來定位到視頻的每一幀?如何實現(xiàn)?
總結(jié)
以上所述是小編給大家介紹的使用canvas實現(xiàn)一個vue彈幕組件功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Vue中textarea自適應(yīng)高度方案的實現(xiàn)
本文主要介紹了Vue中textarea自適應(yīng)高度方案的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01iview+vue實現(xiàn)導(dǎo)入EXCEL預(yù)覽功能
這篇文章主要為大家詳細介紹了iview+vue實現(xiàn)導(dǎo)入EXCEL預(yù)覽功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07