新聞中心
HTML 5中的視頻和音頻中有不少核心的事件,其中有的比較容易理解,基本能從字面就解析了,比如“play”事件就很好理解。而其他有的事件則需要花費(fèi)點(diǎn)心思,特別是“progress”事件。因此,在本文中,將帶領(lǐng)讀者研究HTML 5視頻和音頻中重要的事件,探究這些事件是應(yīng)該在什么時(shí)候使用以及其中的重要相關(guān)屬性。我們也將看下這些事件在當(dāng)今不同瀏覽器中的差異。為了本文的測(cè)試,使用的瀏覽器如下:Opera 12、Chrome 28、IE 10、Firefox 22、Safari 5(桌面版)和Mobile Safari 6(iOS版本)。

播放相關(guān)的事件
我們先來看下視頻和音頻中的playback事件。plackback事件發(fā)生的時(shí)機(jī)在播放媒體或停止媒體中,這個(gè)比較好理解,下面來仔細(xì)研究一下。其中“play”和“pause”事件分別在媒體播放和停止的時(shí)候觸發(fā),但也有一個(gè)“ended”事件,該事件是在媒體播放完畢到達(dá)***的時(shí)候觸發(fā)-無論是正常情況下的結(jié)束或是用戶自己動(dòng)播放條到媒體文件的***。
這兩個(gè)對(duì)應(yīng)事件的觸發(fā)很簡(jiǎn)單,只需要調(diào)用play()和pause()方法就可以了。它們也有對(duì)應(yīng)的屬性,其中.paused屬性默認(rèn)設(shè)置為true,而.ended屬性默認(rèn)是設(shè)置為false的,當(dāng)然當(dāng)媒體文件播放到***的時(shí)候,.ended屬性則變?yōu)閠rue。
然而,在Opera、Safari和IE 10中,請(qǐng)注意有個(gè)區(qū)別,就是即使媒體播放完畢,其中的.paused屬性依然為false(從邏輯上說,媒體已經(jīng)播放完畢了)。這樣一個(gè)實(shí)際的結(jié)果是play/pause按鈕的事件都不會(huì)觸發(fā)了,看下面的例子:
- button.addEventListener('click', function(e)
- {
- if(media.paused)
- {
- media.play();
- }
- else
- {
- media.pause();
- }
- }, false);
也就是說,當(dāng)視頻結(jié)束后,其pause()事件依然能調(diào)用。我們可以通過一個(gè)小技巧去修正這個(gè)問題,如下代碼所示:
- media.addEventListener('ended', function(e)
- {
- media.pause();
- }, false);
也就是在監(jiān)聽ended事件中,主動(dòng)調(diào)用media.pause()方法就可以了。在Firefox和Chrome的***版本中,已經(jīng)修正了這個(gè)問題。
關(guān)于加載事件
加載事件總是在媒體加載(或加載失敗)的時(shí)候發(fā)生。加載事件受到加載媒體狀態(tài)的影響,比如是否使用了preload屬性又或者是媒體是否緩存了。下面我們來逐一分析下其中關(guān)鍵的事件,首先是“l(fā)oadstart”事件,含義是讓瀏覽器剛開始的時(shí)候去尋找獲得數(shù)據(jù)。但要注意的是,loadstart并不意味著就任何數(shù)據(jù)就會(huì)馬上加載,還要看preload屬性的值的設(shè)置。如果preload(預(yù)裝載的值)設(shè)置為“none”的話,則“l(fā)oadstart”事件就是唯一在播放視頻前觸發(fā)的事件。如果preload屬性設(shè)置為“metadata”或者是“auto”,則會(huì)觸發(fā)“progress”和“l(fā)oadmetadata”事件(如果沒預(yù)加載的話,這兩個(gè)事件也會(huì)觸發(fā),但不會(huì)在播放前發(fā)生)。
在下一節(jié)中,我們才學(xué)習(xí)“progress”事件,由于其比較復(fù)雜。我們先來學(xué)習(xí)比較簡(jiǎn)單的“l(fā)oadedmetadata”事件。正如字面的含義,瀏覽器僅僅加載媒體的元數(shù)據(jù)信息而已,比如其長(zhǎng)度.duration(是一個(gè)浮點(diǎn)數(shù)而不是默認(rèn)的NaN)。
當(dāng)然,“l(fā)oadedmetadata”事件只有在確認(rèn)能加載媒體文件后才能加載,換句話說,如果某個(gè)媒體問題文件不能加載(比如404錯(cuò)誤),則會(huì)直接產(chǎn)生error事件,當(dāng)然也不可能繼續(xù)運(yùn)行相關(guān)的播放事件了。
這里,又要提醒用戶有的瀏覽器中是有差別的。在Mobile Safari中,preload的屬性其實(shí)是沒聲明的,就等于設(shè)置為“none”一樣了。但在IE 10中,又有不同了,其中媒體的元數(shù)據(jù)默認(rèn)是自動(dòng)加載的,所以preload設(shè)置為none其實(shí)跟設(shè)置為metadata的作用是一樣的。
在“l(fā)oadedmetadata”事件觸發(fā)后,接下來的重要事件就是“canplay”,這個(gè)是瀏覽器用來確認(rèn)是否已經(jīng)裝載足夠的媒體信息到瀏覽器中能播放一個(gè)事件。如果preload屬性設(shè)置為“auto”,則在數(shù)據(jù)裝載后大概幾秒,“canplay”事件就會(huì)觸發(fā);如果preload設(shè)置為“metadata”或者是“none”,則直到播放開始時(shí)才會(huì)觸發(fā)。這個(gè)規(guī)則對(duì)Chrome瀏覽器來說是例外的,在Chrome中,即使只是加載元數(shù)據(jù)階段,“canplay”事件也會(huì)觸發(fā)。
同時(shí)也有僅接著的事件叫“canplaythrough”,這個(gè)事件其實(shí)是給瀏覽器根據(jù)當(dāng)前網(wǎng)絡(luò)狀況去判斷是否已經(jīng)加載了足夠的媒體片斷而支撐基本的播放。所以這個(gè)事件要在數(shù)據(jù)被預(yù)加載大概幾秒后才會(huì)觸發(fā)。
在實(shí)際情況下,“canplaythrough”事件基本是沒啥作用的,因?yàn)镾afari根本不會(huì)觸發(fā)這個(gè)事件,而Opera和Chrome則在“canplay”事件觸發(fā)后馬上就觸發(fā)這個(gè)事件,只有FireFox和IE 10實(shí)現(xiàn)了這個(gè)事件。
所以實(shí)際上,開發(fā)者最應(yīng)該關(guān)心的是監(jiān)視“progress”事件,以了解媒體到底加載了多少(必要的時(shí)候可以計(jì)算媒體的下載速度)。
Progress事件
接下來我們重點(diǎn)學(xué)習(xí)下progress事件。該事件在數(shù)據(jù)正在下載的時(shí)候會(huì)觸發(fā)。所以當(dāng)preload設(shè)置為none的時(shí)候,progress事件在知道播放事件真正開始前是不會(huì)觸發(fā)的。如果preload設(shè)置為“metadata”,則該事件會(huì)短暫觸發(fā)大概幾秒,然后停止,直到真正的播放行為開始時(shí)才觸發(fā);如果preload設(shè)置為“auto”,則會(huì)觸發(fā)一直直到整個(gè)媒體文件下載完畢。
無論preload如何設(shè)置,一旦用戶開始進(jìn)行播放的行為,則瀏覽器會(huì)開始下載整個(gè)媒體文件,則會(huì)持續(xù)觸發(fā)progress事件,一直直到整個(gè)文件下載完畢,即使視頻被暫停。
當(dāng)數(shù)據(jù)下載后,則我們需要了解如何用時(shí)間表達(dá)這個(gè)progress的事件,則對(duì)接下來深入了解progress事件是十分重要的。當(dāng)數(shù)據(jù)開始加載時(shí),會(huì)創(chuàng)建表示媒體播放時(shí)間的范圍,比如一旦頭10秒的數(shù)據(jù)已經(jīng)加載,則以數(shù)組的方式記錄了開始和結(jié)束時(shí)間,如下的方式表示:
- [0,10]
當(dāng)然,實(shí)際上是會(huì)有多個(gè)時(shí)間范圍存在的,比如用戶手工使用播放器的進(jìn)度條去移動(dòng)到想要的位置,則瀏覽器會(huì)忽略當(dāng)前的時(shí)間范圍而加載新的部分而不是象 Flash那樣重新加載兩個(gè)時(shí)間點(diǎn)之間的部分。
比如我們加載10秒的視頻后,跳到兩分鐘后的片斷繼續(xù)播放另外的10秒,則有兩個(gè)時(shí)間范圍,用如下的方式表達(dá):
- [
- [0,10],
- [120,130]
- ]
假設(shè)用戶這個(gè)時(shí)候又回看舊的片斷,則繼續(xù)又增加一個(gè)時(shí)間范圍的數(shù)組,如:
- [
- [0,10],
- [60,70],
- [120,130]
- ]
如果從60秒開始看到130秒結(jié)束,則***的時(shí)間范圍合拼為:
- [
- [0,10],
- [60,130]
- ]
上面的例子只是簡(jiǎn)單說明在播放媒體中,時(shí)間的范圍是如何運(yùn)作的,當(dāng)然實(shí)際上的數(shù)據(jù)保存不是這個(gè)樣子。實(shí)際上媒體都有一個(gè).buffered對(duì)象以表示時(shí)間范圍。.buffered對(duì)象有一個(gè).length長(zhǎng)度屬性表示有多少段時(shí)間范圍,并且有對(duì)應(yīng)的start()和end()方法, 所以我們可以將buffered的數(shù)據(jù)轉(zhuǎn)換為二維數(shù)組,如下代碼所示:
- var ranges = [];
- for(var i = 0; i < media.buffered.length; i ++)
- {
- ranges.push([
- media.buffered.start(i),
- media.buffered.end(i)
- ]);
***,我們可以自定義progress事件如下:
- media.addEventListener('progress', function()
- {
- var ranges = [];
- for(var i = 0; i < media.buffered.length; i ++)
- {
- ranges.push([
- media.buffered.start(i),
- media.buffered.end(i)
- ]);
- }
- }, false);
有了這個(gè)方法,則我們可以針對(duì)progress事件進(jìn)行一些定制開發(fā)。比如我們可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的播放視頻,并且提供一個(gè)額外的進(jìn)度條,在視頻加載過程中能看到其進(jìn)度。其實(shí)際的運(yùn)行效果請(qǐng)參考:http://jspro.brothercake.com/media-events/progress.html ,下面是一個(gè)運(yùn)行效果截圖:
下面選取其中的代碼片斷講解其核心原理:
- function onprogress()
- {
- //獲得buffered數(shù)據(jù)
- var ranges = [];
- for(var i = 0; i < media.buffered.length; i ++)
- {
- ranges.push([
- media.buffered.start(i),
- media.buffered.end(i)
- ]);
- }
- //獲得在容器中的當(dāng)前進(jìn)度
- var spans = progress.getElementsByTagName('span');
- //如果還沒有加載完畢則繼續(xù)加載
- while(spans.length < media.buffered.length)
- {
- progress.appendChild(document.createElement('span'));
- }
- while(spans.length > media.buffered.length)
- {
- progress.removeChild(progress.lastChild);
- }
- for(var i = 0; i < media.buffered.length; i ++)
- {
- spans[i].style.left = Math.round
- (
- (100 / media.duration) *
- ranges[i][0]
- )
- + '%';
- spans[i].style.width = Math.round
- (
- (100 / media.duration) *
- (ranges[i][1] - ranges[i][0])
- )
- + '%';
- }
- }
在上面的代碼段中,使用的是設(shè)置的寬度去代表進(jìn)度條的每一個(gè)格的寬度,首先獲得buffered數(shù)據(jù),存放到數(shù)據(jù)ranges中,然后判斷媒體文件是否加載完畢,如果還沒加載完畢,則繼續(xù)往DOM中添加標(biāo)簽,而這個(gè)span標(biāo)簽的寬度和樣式則是通過上面的代碼按百分比計(jì)算出來。
***,用戶可以通過http://jspro.brothercake.com/media-events/events.html的例子,學(xué)習(xí)到本文中提到的在媒體加載前、加載中和加載后瀏覽器的相關(guān)事件,在這個(gè)例子中會(huì)輸出相關(guān)的日志。
當(dāng)前標(biāo)題:HTML5中視頻和音頻核心事件講解
當(dāng)前路徑:http://m.5511xx.com/article/dpeghij.html


咨詢
建站咨詢
