小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

閱讀 : HTML5腳本編程

 看見就非常 2012-07-02

本書前面討論過,HTML5規(guī)范定義了很多新HTML標(biāo)記。為了配合這些標(biāo)記的變化,HTML5規(guī)范也用顯著篇幅定義了很多JavaScript API。定義這些API的用意就是簡(jiǎn)化此前實(shí)現(xiàn)起來困難重重的任務(wù),最終簡(jiǎn)化創(chuàng)建動(dòng)態(tài)Web界面的工作。

跨文檔消息傳遞

跨文檔消息傳送(cross-document messaging),有時(shí)候簡(jiǎn)稱為XDM,指的是在來自不同域的頁面間傳遞消息。例如,www.域中的頁面與位于一個(gè)內(nèi)嵌框架中的p2p.域中的頁面通信。在XDM機(jī)制出現(xiàn)之前,要穩(wěn)妥地實(shí)現(xiàn)這種通信需要花很多工夫。XDM把這種機(jī)制規(guī)范化,讓我們能既穩(wěn)妥又簡(jiǎn)單地實(shí)現(xiàn)跨文檔通信。

XDM的核心是postMessage()方法。在HTML5規(guī)范中,除了XDM部分之外的其他部分也會(huì)提到這個(gè)方法名,但都是為了同一個(gè)目的:向另一個(gè)地方傳遞數(shù)據(jù)。對(duì)于XDM而言,“另一個(gè)地方”指的是包含在當(dāng)前頁面中的元素,或者由當(dāng)前頁面彈出的窗口。

postMessage()方法接收兩個(gè)參數(shù):一條消息和一個(gè)表示消息接收方來自哪個(gè)域的字符串。第二個(gè)參數(shù)對(duì)保障安全通信非常重要,可以防止瀏覽器把消息發(fā)送到不安全的地方。來看下面的例子。

//注意:所有支持XDM的瀏覽器也支持iframe的contentWindow屬性

var iframeWindow = document.getElementById("myframe").contentWindow;
iframeWindow.postMessage("A secret", "http://www.");

最后一行代碼嘗試向內(nèi)嵌框架中發(fā)送一條消息,并指定框架中的文檔必須來源于"http:// www."域。如果來源匹配,消息會(huì)傳遞到內(nèi)嵌框架中;否則,postMessage()什么也不做。這一限制可以避免窗口中的位置在你不知情的情況下發(fā)生改變。如果傳給postMessage()的第二個(gè)參數(shù)是"*",則表示可以把消息發(fā)送給來自任何域的文檔,但我們不推薦這樣做。

接收到XDM消息時(shí),會(huì)觸發(fā)window對(duì)象的message事件。這個(gè)事件是以異步形式觸發(fā)的,因此從發(fā)送消息到接收消息(觸發(fā)接收窗口的message事件)可能要經(jīng)過一段時(shí)間的延遲。觸發(fā)message事件后,傳遞給onmessage處理程序的事件對(duì)象包含以下三方面的重要信息。

  • data:作為postMessage()第一個(gè)參數(shù)傳入的字符串?dāng)?shù)據(jù)。
  • origin:發(fā)送消息的文檔所在的域,例如"http://www."。
  • source:發(fā)送消息的文檔的window對(duì)象的代理。這個(gè)代理對(duì)象主要用于在發(fā)送上一條消息的窗口中調(diào)用postMessage()方法。如果發(fā)送消息的窗口來自同一個(gè)域,那這個(gè)對(duì)象就是window。

接收到消息后驗(yàn)證發(fā)送窗口的來源是至關(guān)重要的。就像給postMessage()方法指定第二個(gè)參數(shù),以確保瀏覽器不會(huì)把消息發(fā)送給未知頁面一樣,在onmessage處理程序中檢測(cè)消息來源可以確保傳入的消息來自已知的頁面。基本的檢測(cè)模式如下。

EventUtil.addHandler(window, "message", function(event){

//確保發(fā)送消息的域是已知的域
if (event.origin == "http://www."){

    //處理接收到的數(shù)據(jù)
    processMessage(event.data);

    //可選:向來源窗口發(fā)送回執(zhí)
    event.source.postMessage("Received!", "http://p2p.");
}

});

還是要提醒大家,event.source大多數(shù)情況下只是window對(duì)象的代理,并非實(shí)際的window對(duì)象。換句話說,不能通過這個(gè)代理對(duì)象訪問window對(duì)象的其他任何信息。記住,只通過這個(gè)代理調(diào)用postMessage()就好,這個(gè)方法永遠(yuǎn)存在,永遠(yuǎn)可以調(diào)用。

XDM還有一些怪異之處。首先,postMessage()的第一個(gè)參數(shù)最早是作為“永遠(yuǎn)都是字符串”來實(shí)現(xiàn)的。但后來這個(gè)參數(shù)的定義改了,改成允許傳入任何數(shù)據(jù)結(jié)構(gòu)。可是,并非所有瀏覽器都實(shí)現(xiàn)了這一變化。為保險(xiǎn)起見,使用postMessage()時(shí),最好還是只傳字符串。如果你想傳入結(jié)構(gòu)化的數(shù)據(jù),最佳選擇是先在要傳入的數(shù)據(jù)上調(diào)用JSON.stringify(),通過postMessage()傳入得到的字符串,然后再在onmessage事件處理程序中調(diào)用JSON.parse()。

在通過內(nèi)嵌框架加載其他域的內(nèi)容時(shí),使用XDM是非常方便的。因此,在混搭(mashup)和社交網(wǎng)絡(luò)應(yīng)用中,這種傳遞消息的方法極為常用。有了XDM,包含的頁面可以確保自身不受惡意內(nèi)容的侵?jǐn)_,因?yàn)樗煌ㄟ^XDM與嵌入的框架通信。而XDM也可以在來自相同域的頁面間使用。

支持XDM的瀏覽器有IE8+、Firefox 3.5+、Safari 4+、Opera、Chrome、iOS版Safari及Android版WebKit。XDM已經(jīng)作為一個(gè)規(guī)范獨(dú)立出來,現(xiàn)在它的名字叫Web Messaging,官方頁面是http://dev./html5/postmsg/。

原生拖放

最早在網(wǎng)頁中引入JavaScript拖放功能的是IE4。當(dāng)時(shí),網(wǎng)頁中只有兩種對(duì)象可以拖放:圖像和某些文本。拖動(dòng)圖像時(shí),把鼠標(biāo)放在圖像上,按住鼠標(biāo)不放就可以拖動(dòng)它。拖動(dòng)文本時(shí),要先選中文本,然后可以像拖動(dòng)圖像一樣拖動(dòng)被選中的文本。在IE 4中,唯一有效的放置目標(biāo)是文本框。到了IE5,拖放功能得到擴(kuò)展,添加了新的事件,而且?guī)缀蹙W(wǎng)頁中的任何元素都可以作為放置目標(biāo)。IE5.5更進(jìn)一步,讓網(wǎng)頁中的任何元素都可以拖放。(IE6同樣也支持這些功能。)HTML5以IE的實(shí)例為基礎(chǔ)制定了拖放規(guī)范。Firefox 3.5、Safari 3+和Chrome也根據(jù)HTML5規(guī)范實(shí)現(xiàn)了原生拖放功能。

說到拖放,最有意思的恐怕就是能夠在框架間、窗口間,甚至在應(yīng)用間拖放網(wǎng)頁元素了。瀏覽器對(duì)拖放的支持為實(shí)現(xiàn)這些功能提供了便利。

拖放事件

通過拖放事件,可以控制拖放相關(guān)的各個(gè)方面。其中最關(guān)鍵的地方在于確定哪里發(fā)生了拖放事件,有些事件是在被拖動(dòng)的元素上觸發(fā)的,而有些事件是在放置目標(biāo)上觸發(fā)的。拖動(dòng)某元素時(shí),將依次觸發(fā)下列事件:

(1) dragstart

(2) drag

(3) dragend

按下鼠標(biāo)鍵并開始移動(dòng)鼠標(biāo)時(shí),會(huì)在被拖放的元素上觸發(fā)dragstart事件。此時(shí)光標(biāo)變成“不能放”符號(hào)(圓環(huán)中有一條反斜線),表示不能把元素放到自己上面。拖動(dòng)開始時(shí),可以通過ondragstart事件處理程序來運(yùn)行JavaScript代碼。

觸發(fā)dragstart事件后,隨即會(huì)觸發(fā)drag事件,而且在元素被拖動(dòng)期間會(huì)持續(xù)觸發(fā)該事件。這個(gè)事件與mousemove事件相似,在鼠標(biāo)移動(dòng)過程中,mousemove事件也會(huì)持續(xù)發(fā)生。當(dāng)拖動(dòng)停止時(shí)(無論是把元素放到了有效的放置目標(biāo),還是放到了無效的放置目標(biāo)上),會(huì)觸發(fā)dragend事件。

上述三個(gè)事件的目標(biāo)都是被拖動(dòng)的元素。默認(rèn)情況下,瀏覽器不會(huì)在拖動(dòng)期間改變被拖動(dòng)元素的外觀,但你可以自己修改。不過,大多數(shù)瀏覽器會(huì)為正被拖動(dòng)的元素創(chuàng)建一個(gè)半透明的副本,這個(gè)副本始終跟隨著光標(biāo)移動(dòng)。

當(dāng)某個(gè)元素被拖動(dòng)到一個(gè)有效的放置目標(biāo)上時(shí),下列事件會(huì)依次發(fā)生: (1) dragenter (2) dragover (3)
dragleave或drop

只要有元素被拖動(dòng)到放置目標(biāo)上,就會(huì)觸發(fā)dragenter事件(類似于mouseover事件)。緊隨其后的是dragover事件,而且在被拖動(dòng)的元素還在放置目標(biāo)的范圍內(nèi)移動(dòng)時(shí),就會(huì)持續(xù)觸發(fā)該事件。如果元素被拖出了放置目標(biāo),dragover事件不再發(fā)生,但會(huì)觸發(fā)dragleave事件(類似于mouseout事件)。如果元素被放到了放置目標(biāo)中,則會(huì)觸發(fā)drop事件而不是dragleave事件。上述三個(gè)事件的目標(biāo)都是作為放置目標(biāo)的元素。

自定義放置目標(biāo)

在拖動(dòng)元素經(jīng)過某些無效放置目標(biāo)時(shí),可以看到一種特殊的光標(biāo)(圓環(huán)中有一條反斜線),表示不能放置。雖然所有元素都支持放置目標(biāo)事件,但這些元素默認(rèn)是不允許放置的。如果拖動(dòng)元素經(jīng)過不允許放置的元素,無論用戶如何操作,都不會(huì)發(fā)生drop事件。不過,你可以把任何元素變成有效的放置目標(biāo),方法是重寫dragenter和dragover事件的默認(rèn)行為。例如,假設(shè)有一個(gè)ID為"droptarget"的

元素,可以用如下代碼將它變成一個(gè)放置目標(biāo)。

var droptarget = document.getElementById("droptarget");

EventUtil.addHandler(droptarget, "dragover", function(event){ 
    EventUtil.preventDefault(event);
});

EventUtil.addHandler(droptarget, "dragenter", function(event){
    EventUtil.preventDefault(event);
});

以上代碼執(zhí)行后,你就會(huì)發(fā)現(xiàn)當(dāng)拖動(dòng)著元素移動(dòng)到放置目標(biāo)上時(shí),光標(biāo)變成了允許放置的符號(hào)。當(dāng)然,釋放鼠標(biāo)也會(huì)觸發(fā)drop事件。

在Firefox 3.5+中,放置事件的默認(rèn)行為是打開被放到放置目標(biāo)上的URL。換句話說,如果是把圖像拖放到放置目標(biāo)上,頁面就會(huì)轉(zhuǎn)向圖像文件;而如果是把文本拖放到放置目標(biāo)上,則會(huì)導(dǎo)致無效URL錯(cuò)誤。因此,為了讓Firefox支持正常的拖放,還要取消drop事件的默認(rèn)行為,阻止它打開URL:

EventUtil.addHandler(droptarget, "drop", function(event){
    EventUtil.preventDefault(event); 
});

dataTransfer對(duì)象

只有簡(jiǎn)單的拖放而沒有數(shù)據(jù)變化是沒有什么用的。為了在拖放操作時(shí)實(shí)現(xiàn)數(shù)據(jù)交換,IE 5引入了dataTransfer對(duì)象,它是事件對(duì)象的一個(gè)屬性,用于從被拖動(dòng)元素向放置目標(biāo)傳遞字符串格式的數(shù)據(jù)。因?yàn)樗鞘录?duì)象的屬性,所以只能在拖放事件的事件處理程序中訪問dataTransfer對(duì)象。在事件處理程序中,可以使用這個(gè)對(duì)象的屬性和方法來完善拖放功能。目前,HTML5規(guī)范草案也收入了dataTransfer對(duì)象。

dataTransfer對(duì)象有兩個(gè)主要方法:getData()和setData()。不難想象,getData()可以取得由setData()保存的值。setData()方法的第一個(gè)參數(shù),也是getData()方法唯一的一個(gè)參數(shù),是一個(gè)字符串,表示保存的數(shù)據(jù)類型,取值為"text"或"URL",如下所示:

//設(shè)置和接收文本數(shù)據(jù)
event.dataTransfer.setData("text", "some text");
var text = event.dataTransfer.getData("text");

//設(shè)置和接收URL
event.dataTransfer.setData("URL", "http://www./");
var url = event.dataTransfer.getData("URL");

IE只定義了"text"和"URL"兩種有效的數(shù)據(jù)類型,而HTML5則對(duì)此加以擴(kuò)展,允許指定各種MIME類型??紤]到向后兼容,HTML5也支持"text"和"URL",但這兩種類型會(huì)被映射為"text/plain"和"text/uri-list"。
實(shí)際上,dataTransfer對(duì)象可以為每種MIME類型都保存一個(gè)值。換句話說,同時(shí)在這個(gè)對(duì)象中保存一段文本和一個(gè)URL不會(huì)有任何問題。不過,保存在dataTransfer對(duì)象中的數(shù)據(jù)只能在drop事件處理程序中讀取。如果在ondrop處理程序中沒有讀到數(shù)據(jù),那就是dataTransfer對(duì)象已經(jīng)被銷毀,數(shù)據(jù)也丟失了。

在拖動(dòng)文本框中的文本時(shí),瀏覽器會(huì)調(diào)用setData()方法,將拖動(dòng)的文本以"text"格式保存在dataTransfer對(duì)象中。類似地,在拖放鏈接或圖像時(shí),會(huì)調(diào)用setData()方法并保存URL。然后,在這些元素被拖放到放置目標(biāo)時(shí),就可以通過getData()讀到這些數(shù)據(jù)。當(dāng)然,作為開發(fā)人員,你也可以在dragstart事件處理程序中調(diào)用setData(),手工保存自己要傳輸?shù)臄?shù)據(jù),以便將來使用。

將數(shù)據(jù)保存為文本和保存為URL是有區(qū)別的。如果將數(shù)據(jù)保存為文本格式,那么數(shù)據(jù)不會(huì)得到任何特殊處理。而如果將數(shù)據(jù)保存為URL,瀏覽器會(huì)將其當(dāng)成網(wǎng)頁中的鏈接。換句話說,如果你把它放置到另一個(gè)瀏覽器窗口中,瀏覽器就會(huì)打開該URL。

Firefox在其第5個(gè)版本之前不能正確地將"url"和"text"映射為"text/uri-list"和"text/plain"。但是卻能把"Text"(T大寫)映射為"text/plain"。為了更好地在跨瀏覽器的情況下從dataTransfer對(duì)象取得數(shù)據(jù),最好在取得URL數(shù)據(jù)時(shí)檢測(cè)兩個(gè)值,而在取得文本數(shù)據(jù)時(shí)使用"Text"。

var dataTransfer = event.dataTransfer;

//讀取URL
var url = dataTransfer.getData("url") ||dataTransfer.getData("text/uri-list");

//讀取文本
var text = dataTransfer.getData("Text");

DataTransferExample01.htm

注意,一定要把短數(shù)據(jù)類型放在前面,因?yàn)镮E 10及之前的版本仍然不支持?jǐn)U展的MIME類型名,而它們?cè)谟龅綗o法識(shí)別的數(shù)據(jù)類型時(shí),會(huì)拋出錯(cuò)誤。

dropEffect與effectAllowed

利用dataTransfer對(duì)象,可不光是能夠傳輸數(shù)據(jù),還能通過它來確定被拖動(dòng)的元素以及作為放置目標(biāo)的元素能夠接收什么操作。為此,需要訪問dataTransfer對(duì)象的兩個(gè)屬性:dropEffect和effectAllowed。
其中,通過dropEffect屬性可以知道被拖動(dòng)的元素能夠執(zhí)行哪種放置行為。這個(gè)屬性有下列4個(gè)可能的值。

  • "none":不能把拖動(dòng)的元素放在這里。這是除文本框之外所有元素的默認(rèn)值。
  • "move":應(yīng)該把拖動(dòng)的元素移動(dòng)到放置目標(biāo)。
  • "copy":應(yīng)該把拖動(dòng)的元素復(fù)制到放置目標(biāo)。
  • "link":表示放置目標(biāo)會(huì)打開拖動(dòng)的元素(但拖動(dòng)的元素必須是一個(gè)鏈接,有URL)。

在把元素拖動(dòng)到放置目標(biāo)上時(shí),以上每一個(gè)值都會(huì)導(dǎo)致光標(biāo)顯示為不同的符號(hào)。然而,要怎樣實(shí)現(xiàn)光標(biāo)所指示的動(dòng)作完全取決于你。換句話說,如果你不介入,沒有什么會(huì)自動(dòng)地移動(dòng)、復(fù)制,也不會(huì)打開鏈接??傊?,瀏覽器只能幫你改變光標(biāo)的樣式,而其他的都要靠你自己來實(shí)現(xiàn)。要使用dropEffect屬性,必須在ondragenter事件處理程序中針對(duì)放置目標(biāo)來設(shè)置它。

dropEffect屬性只有搭配effectAllowed屬性才有用。effectAllowed屬性表示允許拖動(dòng)元素的哪種dropEffect,effectAllowed屬性可能的值如下。

  • "uninitialized":沒有給被拖動(dòng)的元素設(shè)置任何放置行為。
  • "none":被拖動(dòng)的元素不能有任何行為。
  • "copy":只允許值為"copy"的dropEffect。
  • "link":只允許值為"link"的dropEffect。
  • "move":只允許值為"move"的dropEffect。
  • "copyLink":允許值為"copy"和"link"的dropEffect。
  • "copyMove":允許值為"copy"和"move"的dropEffect。
  • "linkMove":允許值為"link"和"move"的dropEffect。
  • "all":允許任意dropEffect。

必須在ondragstart事件處理程序中設(shè)置effectAllowed屬性。

假設(shè)你想允許用戶把文本框中的文本拖放到一個(gè)

元素中。首先,必須將dropEffect和effectAllowed設(shè)置為"move"。但是,由于
元素的放置事件的默認(rèn)行為是什么也不做,所以文本不可能自動(dòng)移動(dòng)。重寫這個(gè)默認(rèn)行為,就能從文本框中移走文本。然后你就可以自己編寫代碼將文本插入到
中,這樣整個(gè)拖放操作就完成了。如果你將dropEffect和effectAllowed的值設(shè)置為"copy",那就不會(huì)自動(dòng)移走文本框中的文本。

Firefox 5及之前的版本在處理effectAllowed屬性時(shí)有一個(gè)問題,即如果你在代碼中設(shè)置了這個(gè)屬性的值,那不一定會(huì)觸發(fā)drop事件
。

可拖動(dòng)

默認(rèn)情況下,圖像、鏈接和文本是可以拖動(dòng)的,也就是說,不用額外編寫代碼,用戶就可以拖動(dòng)它們。文本只有在被選中的情況下才能拖動(dòng),而圖像和鏈接在任何時(shí)候都可以拖動(dòng)。

讓其他元素可以拖動(dòng)也是可能的。HTML5為所有HTML元素規(guī)定了一個(gè)draggable屬性,表示元素是否可以拖動(dòng)。圖像和鏈接的draggable屬性自動(dòng)被設(shè)置成了true,而其他元素這個(gè)屬性的默認(rèn)值都是false。要想讓其他元素可拖動(dòng),或者讓圖像或鏈接不能拖動(dòng),都可以設(shè)置這個(gè)屬性。例如:

<!-- 讓這個(gè)圖像不可以拖動(dòng) -->
<img src="smile.gif" draggable="false" alt="Smiley face">

<!-- 讓這個(gè)元素可以拖動(dòng) -->
<div draggable="true">...</div>

支持draggable屬性的瀏覽器有IE 10+、Firefox 4+、Safari 5+和Chrome。Opera 11.5及之前的版本都不支持HTML5的拖放功能。另外,為了讓Firefox支持可拖動(dòng)屬性,還必須添加一個(gè)ondragstart事件處理程序,并在dataTransfer對(duì)象中保存一些信息。

在IE9及更早版本中,通過mousedown事件處理程序調(diào)用dragDrop()能夠讓任何元素可拖動(dòng)。而在Safari 4及之前版本中,必須額外給相應(yīng)元素設(shè)置CSS樣式–khtml-user-drag: element。

其他成員

HTML5規(guī)范規(guī)定dataTransfer對(duì)象還應(yīng)該包含下列方法和屬性。

  • addElement(element):為拖動(dòng)操作添加一個(gè)元素。添加這個(gè)元素只影響數(shù)據(jù)(即增加作為拖動(dòng)源而響應(yīng)回調(diào)的對(duì)象),不會(huì)影響拖動(dòng)操作時(shí)頁面元素的外觀。在寫作本書時(shí),只有Firefox 3.5+實(shí)現(xiàn)了這個(gè)方法。
  • clearData(format):清除以特定格式保存的數(shù)據(jù)。實(shí)現(xiàn)這個(gè)方法的瀏覽器有IE、Fireforx 3.5+、Chrome和Safari 4+。
  • setDragImage(element, x, y):指定一幅圖像,當(dāng)拖動(dòng)發(fā)生時(shí),顯示在光標(biāo)下方。這個(gè)方法接收的三個(gè)參數(shù)分別是要顯示的HTML元素和光標(biāo)在圖像中的x、y坐標(biāo)。其中,HTML元素可以是一幅圖像,也可以是其他元素。是圖像則顯示圖像,是其他元素則顯示渲染后的元素。實(shí)現(xiàn)這個(gè)方法的瀏覽器有Firefox 3.5+、Safari 4+和Chrome。
  • types:當(dāng)前保存的數(shù)據(jù)類型。這是一個(gè)類似數(shù)組的集合,以"text"這樣的字符串形式保存著數(shù)據(jù)類型。實(shí)現(xiàn)這個(gè)屬性的瀏覽器有IE10+、Firefox 3.5+和Chrome。

媒體元素

隨著音頻和視頻在Web上的迅速流行,大多數(shù)提供富媒體內(nèi)容的站點(diǎn)為了保證跨瀏覽器兼容性,不得不選擇使用Flash。HTML5新增了兩個(gè)與媒體相關(guān)的標(biāo)簽,讓開發(fā)人員不必依賴任何插件就能在網(wǎng)頁中嵌入跨瀏覽器的音頻和視頻內(nèi)容。這兩個(gè)標(biāo)簽就是和。

這兩個(gè)標(biāo)簽除了能讓開發(fā)人員方便地嵌入媒體文件之外,都提供了用于實(shí)現(xiàn)常用功能的JavaScript API,允許為媒體創(chuàng)建自定義的控件。這兩個(gè)元素的用法如下。

<!-- 嵌入視頻 -->
<video src="conference.mpg" id="myVideo">Video player not available.</video>

<!-- 嵌入音頻 -->
<audio src="song.mp3" id="myAudio">Audio player not available.</audio>

使用這兩個(gè)元素時(shí),至少要在標(biāo)簽中包含src屬性,指向要加載的媒體文件。還可以設(shè)置width和height屬性以指定視頻播放器的大小,而為poster屬性指定圖像的URI可以在加載視頻內(nèi)容期間顯示一幅圖像。另外,如果標(biāo)簽中有controls屬性,則意味著瀏覽器應(yīng)該顯示UI控件,以便用戶直接操作媒體。位于開始和結(jié)束標(biāo)簽之間的任何內(nèi)容都將作為后備內(nèi)容,在瀏覽器不支持這兩個(gè)媒體元素的情況下顯示。

因?yàn)椴⒎撬袨g覽器都支持所有媒體格式,所以可以指定多個(gè)不同的媒體來源。為此,不用在標(biāo)簽中指定src屬性,而是要像下面這樣使用一或多個(gè)元素。

<!-- 嵌入視頻 -->
<video id="myVideo">
  <source src="conference.webm" type="video/webm; codecs='vp8, vorbis'">
  <source src="conference.ogv" type="video/ogg; codecs='theora, vorbis'">
  <source src="conference.mpg">
  Video player not available.
</video>

<!-- 嵌入音頻 -->
<audio id="myAudio">
  <source src="song.ogg" type="audio/ogg">
  <source src="song.mp3" type="audio/mpeg">
  Audio player not available.
</audio>

關(guān)于視頻和音頻編解碼器的內(nèi)容超出了本書討論的范圍。作者在此只想告訴大家,不同的瀏覽器支持不同的編解碼器,因此一般來說指定多種格式的媒體來源是必需的。支持這兩個(gè)媒體元素的瀏覽器有IE9+、Firefox 3.5+、Safari 4+、Opera 10.5+、Chrome、iOS版Safari和Android版WebKit。

屬性

和元素都提供了完善的JavaScript接口。下表列出了這兩個(gè)元素共有的屬性,通過這些屬性可以知道媒體的當(dāng)前狀態(tài)。

enter image description here

事件

除了大量屬性之外,這兩個(gè)媒體元素還可以觸發(fā)很多事件。這些事件監(jiān)控著不同的屬性的變化,這些變化可能是媒體播放的結(jié)果,也可能是用戶操作播放器的結(jié)果。下表列出了媒體元素相關(guān)的事件。

enter image description here

這些事件之所以如此具體,就是為了讓開發(fā)人員只使用少量HTML和JavaScript(與創(chuàng)建Flash影片相比)即可編寫出自定義的音頻/視頻播放器。

自定義媒體播放器

使用和元素的play()和pause()方法,可以手工控制媒體文件的播放。組合使用屬性、事件和這兩個(gè)方法,很容易創(chuàng)建一個(gè)自定義的媒體播放器,如下面的例子所示。

<div class="mediaplayer"> 
    <div class="video">
        <video id="player" src="movie.mov" poster="mymovie.jpg"
               width="300" height="200">
            Video player not available.
        </video>
    </div>
    <div class="controls">
        <input type="button" value="Play" id="video-btn">
        <span id="curtime">0</span>/<span id="duration">0</span>
    </div>
</div>

VideoPlayerExample01.htm

以上基本的HTML再加上一些JavaScript就可以變成一個(gè)簡(jiǎn)單的視頻播放器。以下就是JavaScript代碼。

//取得元素的引用
var player = document.getElementById("player"),
    btn = document.getElementById("video-btn"),
    curtime = document.getElementById("curtime"),
    duration = document.getElementById("duration");

//更新播放時(shí)間
duration.innerHTML = player.duration;


//為按鈕添加事件處理程序
EventUtil.addHandler(btn, "click", function(event){
    if (player.paused){
        player.play();
        btn.value = "Pause";
    } else {
        player.pause();
        btn.value = "Play";
    }
});

//定時(shí)更新當(dāng)前時(shí)間
setInterval(function(){
    curtime.innerHTML = player.currentTime;
}, 250);

VideoPlayerExample01.htm

以上JavaScript代碼給按鈕添加了一個(gè)事件處理程序,單擊它能讓視頻在暫停時(shí)播放,在播放時(shí)暫停。通過元素的load事件處理程序,設(shè)置了加載完視頻后顯示播放時(shí)間。最后,設(shè)置了一個(gè)計(jì)時(shí)器,以更新當(dāng)前顯示的時(shí)間。你可以進(jìn)一步擴(kuò)展這個(gè)視頻播放器,監(jiān)聽更多事件,利用更多屬性。而同樣的代碼也可以用于元素,以創(chuàng)建自定義的音頻播放器。

檢測(cè)編解碼器的支持情況

如前所述,并非所有瀏覽器都支持和的所有編解碼器,而這基本上就意味著你必須提供多個(gè)媒體來源。不過,也有一個(gè)JavaScript API能夠檢測(cè)瀏覽器是否支持某種格式和編解碼器。這兩個(gè)媒體元素都有一個(gè)canPlayType()方法,該方法接收一種格式/編解碼器字符串,返回"probably"、"maybe"或""( 空字符串)??兆址羌僦担虼丝梢韵裣旅孢@樣在if語句中使用canPlayType():

if (audio.canPlayType("audio/mpeg")){
    //進(jìn)一步處理
}

而"probably"和"maybe"都是真值,因此在if語句的條件測(cè)試中可以轉(zhuǎn)換成true。
如果給canPlayType()傳入了一種MIME類型,則返回值很可能是"maybe"或空字符串。這是因?yàn)槊襟w文件本身只不過是音頻或視頻的一個(gè)容器,而真正決定文件能否播放的還是編碼的格式。在同時(shí)傳入MIME類型和編解碼器的情況下,可能性就會(huì)增加,返回的字符串會(huì)變成"probably"。下面來看幾個(gè)例子。

var audio = document.getElementById("audio-player");

//很可能"maybe"
if (audio.canPlayType("audio/mpeg")){
    //進(jìn)一步處理
}

//可能是"probably"
if (audio.canPlayType("audio/ogg; codecs=\"vorbis\"")){
    //進(jìn)一步處理
}

注意,編解碼器必須用引號(hào)引起來才行。下表列出了已知的已得到支持的音頻格式和編解碼器。

enter image description here

Audio類型

元素還有一個(gè)原生的JavaScript構(gòu)造函數(shù)Audio,可以在任何時(shí)候播放音頻。從同為DOM元素的角度看,Audio與Image很相似,但Audio不用像Image那樣必須插入到文檔中。只要?jiǎng)?chuàng)建一個(gè)新實(shí)例,并傳入音頻源文件即可。

var audio = new Audio("sound.mp3");
EventUtil.addHandler(audio, "canplaythrough", function(event){
    audio.play();
}); 

創(chuàng)建新的Audio實(shí)例即可開始下載指定的文件。下載完成后,調(diào)用play()就可以播放音頻。
在iOS中,調(diào)用play()時(shí)會(huì)彈出一個(gè)對(duì)話框,得到用戶的許可后才能播放聲音。如果想在一段音頻播放后再播放另一段音頻,必須在onfinish事件處理程序中調(diào)用play()方法。

歷史狀態(tài)管理

歷史狀態(tài)管理是現(xiàn)代Web應(yīng)用開發(fā)中的一個(gè)難點(diǎn)。在現(xiàn)代Web應(yīng)用中,用戶的每次操作不一定會(huì)打開一個(gè)全新的頁面,因此“后退”和“前進(jìn)”按鈕也就失去了作用,導(dǎo)致用戶很難在不同狀態(tài)間切換。要解決這個(gè)問題,首選使用hashchange事件(第13章曾討論過)。HTML5通過更新history對(duì)象為管理歷史狀態(tài)提供了方便。

通過hashchange事件,可以知道URL的參數(shù)什么時(shí)候發(fā)生了變化,即什么時(shí)候該有所反應(yīng)。而通過狀態(tài)管理API,能夠在不加載新頁面的情況下改變?yōu)g覽器的URL。為此,需要使用history.pushState()方法,該方法可以接收三個(gè)參數(shù):狀態(tài)對(duì)象、新狀態(tài)的標(biāo)題和可選的相對(duì)URL。例如:

history.pushState({name:"Nicholas"}, "Nicholas' page", "nicholas.html");

執(zhí)行pushState()方法后,新的狀態(tài)信息就會(huì)被加入歷史狀態(tài)棧,而瀏覽器地址欄也會(huì)變成新的相對(duì)URL。但是,瀏覽器并不會(huì)真的向服務(wù)器發(fā)送請(qǐng)求,即使?fàn)顟B(tài)改變之后查詢location.href也會(huì)返回與地址欄中相同的地址。另外,第二個(gè)參數(shù)目前還沒有瀏覽器實(shí)現(xiàn),因此完全可以只傳入一個(gè)空字符串,或者一個(gè)短標(biāo)題也可以。而第一個(gè)參數(shù)則應(yīng)該盡可能提供初始化頁面狀態(tài)所需的各種信息。

因?yàn)閜ushState()會(huì)創(chuàng)建新的歷史狀態(tài),所以你會(huì)發(fā)現(xiàn)“后退”按鈕也能使用了。按下“后退”按鈕,會(huì)觸發(fā)window對(duì)象的popstate事件 。popstate事件的事件對(duì)象有一個(gè)state屬性,這個(gè)屬性就包含著當(dāng)初以第一個(gè)參數(shù)傳遞給pushState()的狀態(tài)對(duì)象。

EventUtil.addHandler(window, "popstate", function(event){
    var state = event.state;
    if (state){   //第一個(gè)頁面加載時(shí)state為空
        processState(state);
    }
});

得到這個(gè)狀態(tài)對(duì)象后,必須把頁面重置為狀態(tài)對(duì)象中的數(shù)據(jù)表示的狀態(tài)(因?yàn)闉g覽器不會(huì)自動(dòng)為你做這些)。記住,瀏覽器加載的第一個(gè)頁面沒有狀態(tài),因此單擊“后退”按鈕返回瀏覽器加載的第一個(gè)頁面時(shí),event.state值為null。

要更新當(dāng)前狀態(tài),可以調(diào)用replaceState(),傳入的參數(shù)與pushState()的前兩個(gè)參數(shù)相同。調(diào)用這個(gè)方法不會(huì)在歷史狀態(tài)棧中創(chuàng)建新狀態(tài),只會(huì)重寫當(dāng)前狀態(tài)。

history.replaceState({name:"Greg"}, "Greg's page");

支持HTML5歷史狀態(tài)管理的瀏覽器有Firefox 4+、Safari 5+、Opera 11.5+和Chrome。在Safari和Chrome中,傳遞給pushState()或replaceState()的狀態(tài)對(duì)象中不能包含DOM元素。而Firefox支持在狀態(tài)對(duì)象中包含DOM元素。Opera還支持一個(gè)history.state屬性,它返回當(dāng)前狀態(tài)的狀態(tài)對(duì)象。


小結(jié)

HTML5除了定義了新的標(biāo)記規(guī)則,還定義了一些JavaScript API。這些API是為了讓開發(fā)人員創(chuàng)建出更好的、能夠與桌面應(yīng)用媲美的用戶界面而設(shè)計(jì)的。本章討論了如下API。

  • 跨文檔消息傳遞API能夠讓我們?cè)诓唤档屯床呗园踩缘那疤嵯?,在來自不同域的文檔間傳遞消息。
  • 原生拖放功能讓我們可以方便地指定某個(gè)元素可拖動(dòng),并在操作系統(tǒng)要放置時(shí)做出響應(yīng)。還可以創(chuàng)建自定義的可拖動(dòng)元素及放置目標(biāo)。
  • 新的媒體元素和擁有自己的與音頻和視頻交互的API。并非所有瀏覽器支持所有的媒體格式,因此應(yīng)該使用canPlayType()檢查瀏覽器是否支持特定的格式。
  • 歷史狀態(tài)管理讓我們不必卸載當(dāng)前頁面即可修改瀏覽器的歷史狀態(tài)棧。有了這種機(jī)制,用戶就可以通過“后退”和“前進(jìn)”按鈕在頁面狀態(tài)間切換,而這些狀態(tài)完全由JavaScript進(jìn)行控制。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多