成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

彈幕,是怎樣練成的?

lwx12525 / 2595人閱讀

說(shuō)起彈幕看過(guò)視頻的都不會(huì)陌生,那滿屏充滿著飄逸評(píng)論的效果,讓人如癡如醉,無(wú)法自拔

最近也是因?yàn)樵趯W(xué)習(xí)關(guān)于 canvas 的知識(shí),所以今天就想和大家分享一個(gè)關(guān)于彈幕的故事

那么究竟彈幕是怎樣煉成的呢? 我們且往下看(look)

看什么?看效果

效果圖已經(jīng)呈現(xiàn)給各位了,那么是不是有點(diǎn)小激動(dòng)呢?是的,感慨萬(wàn)分,思緒寧亂,無(wú)語(yǔ)凝噎

無(wú)論以后我們的工作中是否會(huì)遇到這樣的需求,也請(qǐng)給自己一個(gè)增加技能的機(jī)會(huì)吧??!
本次彈幕的效果,項(xiàng)目結(jié)構(gòu)如下圖所示

項(xiàng)目整體已經(jīng)給出,那么我們就擼起袖子加油干吧。

讓彈幕飛

上面我們提到了 canvas 的事情,所以呢,這就是制作彈幕了。我們利用 canvas 繪圖來(lái)實(shí)現(xiàn)彈幕的功能

首先,我們先給出html的結(jié)構(gòu)

// index.html文件

聽(tīng)媽媽的話 - 周杰倫

// 引入index.js文件用來(lái)實(shí)現(xiàn)彈幕功能

結(jié)構(gòu)相對(duì)來(lái)說(shuō)沒(méi)什么高級(jí)的內(nèi)容,主要就是寫上了 canvas 標(biāo)簽還有 video 標(biāo)簽,他們才是視頻網(wǎng)站彈幕的絕佳拍檔

那么不再賣關(guān)子了,趕緊進(jìn)行主要活動(dòng)吧

模擬數(shù)據(jù)

// index.js文件
let data = [
    {value: "周杰倫的聽(tīng)媽媽的話,讓我反復(fù)循環(huán)再循環(huán)", time: 5, color: "red", speed: 1, fontSize: 22},
    {value: "想快快長(zhǎng)大,才能保護(hù)她", time: 10, color: "#00a1f5", speed: 1, fontSize: 30},
    {value: "聽(tīng)媽媽的話吧,晚點(diǎn)再戀愛(ài)吧!愛(ài)呢?", time: 15},
];

數(shù)據(jù)里代表了什么:

value:代表彈幕的內(nèi)容 (必填)

time:代表彈幕展現(xiàn)的時(shí)間 (必填)

color:代表彈幕文字的顏色

speed:代表彈幕飄過(guò)的速度

fontSize:代表彈幕文字的大小

opacity:代表彈幕文字的透明度

除了彈幕的內(nèi)容和展現(xiàn)的時(shí)間外,其他都是可選的,模擬的數(shù)據(jù)里沒(méi)有這些參數(shù)也沒(méi)關(guān)系的

獲取 dom 元素

// index.js文件 
// 模擬數(shù)據(jù)
...省略
// 獲取到所有需要的dom元素
let doc = document;
let canvas = doc.getElementById("canvas");
let video = doc.getElementById("video");
let $txt = doc.getElementById("text");
let $btn = doc.getElementById("btn");
let $color = doc.getElementById("color");
let $range = doc.getElementById("range");

Canvas渲染彈幕

下面我們將用面向?qū)ο蟮姆绞絹?lái)實(shí)現(xiàn)canvas繪制彈幕的功能,之所以選擇用這種方式主要是方便復(fù)用和后續(xù)添加方法;

下面我們先來(lái)創(chuàng)建一個(gè)CanvasBarrage類,主要用做canvas來(lái)渲染整個(gè)彈幕;
在實(shí)現(xiàn)之前,我們先來(lái)調(diào)用一下,看看是如何創(chuàng)建實(shí)例的。

// index.js文件
// 模擬數(shù)據(jù)
...省略
// 獲取到所有需要的dom元素
...省略
// 創(chuàng)建CanvasBarrage類
class CanvasBarrage {
    // todo
}
// 創(chuàng)建CanvasBarrage實(shí)例
let canvasBarrage = new CanvasBarrage(canvas, video, { data });

實(shí)現(xiàn) CanvasBarrage


我們?cè)凇暗玫剿械膹椖幌ⅰ蹦抢?,通過(guò)數(shù)組的 map 方法返回的還是個(gè)數(shù)組,不過(guò)返回的內(nèi)容是一個(gè) Barrage類,這是為什么呢?

還記得之前說(shuō)過(guò)么,用類的好處就是方便擴(kuò)展,后續(xù)再添加方法的話可以直接在該類中添加即可。
所以我們也不推崇直接map方法里直接返回一個(gè){}這種形式

// 不推薦 
this.barrages = this.data.map(item => { item });

說(shuō)到這里我們還要先寫一下Barrage這個(gè)類,不然接下來(lái)的console.log(this)會(huì)因?yàn)檎也坏紹arrage類而報(bào)錯(cuò)

// index.js文件
++++++++++++++++++++++

// 創(chuàng)建Barrage類,用來(lái)實(shí)例化每一個(gè)彈幕元素
class Barrage {
   constructor(obj, ctx) {        // todo    }
}

 ++++++++++++++++++++++
class CanvasBarrage {    ...省略}

Now,通過(guò)上面代碼中的console.log(this),我們可以看到,所有掛載到this實(shí)例上的屬性和原型上的方法都呈現(xiàn)眼前了

render 一下

接著上面的 CanvasBarrage 類里 render 方法繼續(xù)寫,我們來(lái)把 todo 完成

todo都做了什么?

1、清除之前畫布所有的繪制,防止繪制重疊的影響

this.clear()

2、渲染真正的彈幕數(shù)據(jù) (還未實(shí)現(xiàn))

this.renderBarrage()

3、判斷是否繼續(xù)渲染彈幕

this.isPaused為false時(shí)表示為播放狀態(tài)

4、遞歸調(diào)用render

通過(guò)requestAnimationFrame來(lái)遞歸調(diào)用render

要比setInterval這樣的方式好很多

渲染整個(gè)彈幕 render 方法就完成了,那么要繼續(xù)寫了,應(yīng)該是剛才未實(shí)現(xiàn)的 renderBarrage 方法了

But,在此之前,我們要先寫個(gè)別的,它就是Barrage類
因?yàn)檫€需要它來(lái)大顯身手一下呢,每一個(gè)彈幕的實(shí)例都由它來(lái)制造

創(chuàng)建 Barrage 類

彈幕制造者來(lái)了,下面我們就來(lái)實(shí)現(xiàn)一下這個(gè)Barrage類,看它都具備哪些屬性和方法,繼續(xù)todo吧

todo都做了什么?

1、從傳入的obj中取到必要的value和time

this.value = obj.value; // 內(nèi)容 
this.time = obj.time;   // 時(shí)間

2、初始化彈幕

對(duì)每個(gè)彈幕所需的參數(shù)進(jìn)行設(shè)置,如果obj上沒(méi)有,就取默認(rèn)參數(shù)

計(jì)算每個(gè)彈幕的寬度

由于不能直接操縱canvas畫布里的元素,所以先創(chuàng)建一個(gè)p標(biāo)簽

p標(biāo)簽的寬度即為彈幕的寬 -> this.width = p.clientWidt

設(shè)置每個(gè)彈幕的x和y坐標(biāo) (起始位置)

橫向x坐標(biāo)起始位置都是從右邊進(jìn)入,即:畫布的寬度

this.x = this.context.canvas.width

縱向y坐標(biāo)起始位置是不固定的,選在畫布之內(nèi)的任意位置出現(xiàn)

this.y = this.context.canvas.height * Math.random()

處理彈幕超出畫布區(qū)域

canvas是按照字號(hào)基線來(lái)展示字體的,如果小于這個(gè)字號(hào)大小

this.y = this.fontSize

如果大于了畫布高度 - 字號(hào)大小

this.y = this.context.canvas.height - this.fontSize

3、渲染每個(gè)彈幕

繪制文本需要設(shè)置文本的字體字號(hào)、顏色和文本的內(nèi)容與坐標(biāo)

字體字號(hào)api

this.context.ctx.font = ${this.value}px Arial

顏色api

this.context.ctx.fillStyle = this.color

內(nèi)容與坐標(biāo)api

this.context.ctx.fillText(this.value, this.x, this.y)

以上三步就是整個(gè)Barrage類所做的事情了。Barrage這個(gè)類都已經(jīng)敲完了,那么接下來(lái)開始真正的渲染步驟吧

renderBarrage才是主角

此時(shí)我們?cè)偬砑右粋€(gè)觸發(fā)彈幕的事件,讓彈幕飛起來(lái)


大家一起寫到了這里,也是時(shí)候展示一下成果了,往下看

別急,讓彈幕再飛一會(huì)兒

渲染彈幕的功能,我們已經(jīng)完成了,接下來(lái)讓我們馬不停蹄的寫下如何發(fā)彈幕吧。別猶豫,開擼?。?!

發(fā)彈幕

發(fā)彈幕相對(duì)來(lái)說(shuō)還是很簡(jiǎn)單的,獲取到 value, time, color, fontSize 之后把他們當(dāng)作對(duì)象傳給 CanvasBarrage 的 add方法進(jìn)行添加就好了
下面我們?cè)賹懸幌耡dd方法,回到CanvasBarrage類里繼續(xù)寫

// index.js文件
class CanvasBarrage {
    constructor() { ...省略}
    render() { ...省略 }
    renderBarrage() { ...省略 }
    clear() { ...省略 }
    +++++++++++++++++++++++++++
    add(obj) {
        // 實(shí)際上就是往barrages數(shù)組里再添加一項(xiàng)Barrage的實(shí)例而已
        this.barrages.push(new Barrage(obj, this));
    }
    +++++++++++++++++++++++++++
}

完成,漂亮,看看效果吧

寫到這里我們已經(jīng)完成了視頻網(wǎng)站上的彈幕功能了,可喜可賀
下面我們?cè)賮?lái)完善一下視頻播放時(shí)對(duì)彈幕的播放處理吧

暫停和拖動(dòng)

暫停就停止渲染彈幕

// index.js文件
   ...省略
   // 播放
   video.addEventListener("play", () => {
       canvasBarrage.isPaused = false;
       canvasBarrage.render();
   });
   +++++++++++++++++++++++++++++++++++++++
   // 暫停
   video.addEventListener("pause", () => {
       // isPaused設(shè)為true表示暫停播放
       canvasBarrage.isPaused = true;
   });
   +++++++++++++++++++++++++++++++++++++++

回放時(shí)需要重新渲染該時(shí)刻的彈幕

  // index.js文件
  
  // 暫停
  video.addEventListener("pause", () => {
      canvasBarrage.isPaused = true;
  });
  +++++++++++++++++++++++++++++++++++++++
  // 拖動(dòng)進(jìn)度條時(shí)觸發(fā)seeked事件
  video.addEventListener("seeked", () => {
      // 調(diào)用CanvasBarrage類的replay方法進(jìn)行回放,重新渲染彈幕
      canvasBarrage.replay();
  });
  +++++++++++++++++++++++++++++++++++++++

讓我們?cè)俅位氐紺anvasBarrage這個(gè)類上

OK,寫到這里,所有關(guān)于彈幕功能的代碼就全部結(jié)束了??!
如果工作中讓你開發(fā)彈幕功能,你也可以在多敲幾遍以上代碼之后,得心應(yīng)手的保證完成任務(wù)了。
敬請(qǐng)期待,下節(jié)更精彩

接下來(lái)我們?cè)倮?WebSocket 和 redis 來(lái)進(jìn)行一下較為實(shí)戰(zhàn)的功能吧。

作者:chenhongdong
來(lái)源:
https://juejin.im/post/5be54a...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99996.html

相關(guān)文章

  • 一文解鎖BILIBILI、ACFUN等彈幕網(wǎng)站如何審核視頻

    摘要:歡迎訪問(wèn)網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。網(wǎng)易云易盾智能反垃圾服務(wù),基于網(wǎng)易年專業(yè)的反垃圾經(jīng)驗(yàn),以及積累的億級(jí)別的海量數(shù)據(jù),為客戶提供極速智能的廣告過(guò)濾智能鑒黃暴恐識(shí)別涉政檢測(cè)云服務(wù),助力打造互聯(lián)網(wǎng)純凈內(nèi)容生態(tài)。文章來(lái)源網(wǎng)易云社區(qū) 歡迎訪問(wèn)網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。 人工審核對(duì)于A站和B站都是很重要的。 AcFun稿件審核通行標(biāo)準(zhǔn)(V1.1) 表明,要審核的東西...

    劉德剛 評(píng)論0 收藏0
  • 你只知道別人很牛,但你知道那些編程水平很高的程序員怎么成的嗎?

    摘要:要達(dá)到水平很高的程序員,第一要找能提供優(yōu)質(zhì)實(shí)踐機(jī)會(huì)的大廠,第二要在諸如高并發(fā)或機(jī)器學(xué)習(xí)的項(xiàng)目里多解決實(shí)際問(wèn)題,第三還要不斷跳槽,不斷地找更優(yōu)質(zhì)的平臺(tái)和更優(yōu)質(zhì)的項(xiàng)目機(jī)會(huì)。 ...

    booster 評(píng)論0 收藏0
  • 我的Java開發(fā)之路

    摘要:提高有了入門的基礎(chǔ),開始自學(xué)當(dāng)時(shí)流行的三大框架和。業(yè)余的時(shí)間,經(jīng)常在上閑逛,看一些博客或開源的代碼。 最近有一位小伙伴通過(guò)公眾號(hào)給我留言, 我參加工作沒(méi)多久,看著圈里的技術(shù)大牛,特別羨慕,也渴望成為技術(shù)大牛,想讓您分享一下從小白到大牛是怎樣練成的,我該如何提高自己 首先,謝謝這位小伙伴的一直關(guān)注。其次,我并不是大牛,只是早搬了幾年的磚而已,不過(guò)可以分享一下我的Java開發(fā)之路。 入門 ...

    lidashuang 評(píng)論0 收藏0
  • 彈幕給 PPD 生個(gè)孩子

    摘要:使用的的方法實(shí)現(xiàn)了文字滾動(dòng)我們需要做一些準(zhǔn)備工作例如我們?yōu)榱俗審椖豢梢宰冾伾覀儗懥讼旅孢@個(gè)方法。判斷存儲(chǔ)彈幕信息的數(shù)據(jù)是否為空隨機(jī)抽取數(shù)組中的一個(gè)元素之后把它追加到這個(gè)中執(zhí)行文字滾動(dòng)的方法。 怎樣才能跑起來(lái)我寫的彈幕程序 資源下載 申請(qǐng)野狗后端云賬號(hào)注冊(cè) 創(chuàng)建應(yīng)用:showImg(https://segmentfault.com/img/remote/146000000683932...

    linkFly 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<