1. 程式人生 > >《JavaScript高級程序設計》筆記:HTML5腳本編程(16)

《JavaScript高級程序設計》筆記:HTML5腳本編程(16)

list func 調用 無效 src 核心 參數 origin mouse

跨文檔消息傳遞

跨文檔消息傳遞(cross-document messaging),有時候簡稱為XDM,指的是在來自不同域的頁面間傳遞消息。例如,www.wrox.com域中的頁面與位於一個內嵌框架中的p2p.wrox.com域中的頁面通信。

XDM的核心是postMessage()方法。在HTML5規範中,除了XDM部分之外的其他部分也會提到這個方法名,但都是為了同一個目的:向另一個地方傳遞數據。對於XDM而言,“另一個地方”指的是包含在當前頁面中的<iframe>元素,或者由當前頁面彈出的窗口。

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

//註意所有支持XDM的瀏覽器也支持iframe的contentWindow屬性
var iframeWindow = document.getElementById("myframe").contentWindow;
iframeWindow.postMessage("A secret","http://www.wrox.com");

最後一行代碼嘗試向內嵌框架中發送一條消息,並指定框架中的文檔必須來源於http:www.wrox.com域。如果來源匹配,消息會傳遞到內嵌框架中;否則,postMessage()什麽也不做。如果傳給postMessage()的第二個參數是“*”,則表示可以把消息發送給來自任何域的文檔,但我們不推薦這樣做。

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

  • data:作為postMessage()第一個參數傳入的字符串數據。
  • origin:發送消息的文檔所在的域,例如"http://www.wrox.com"。
  • source:發送消息的文檔的window對象的代理。這個代理對象主要用於在發送上一條消息的窗口中調用postMessage()方法。如果發送消息的窗口來自同一個域,那這個對象就是window。
window.addEventListener("message",function(event){
    if(event.origin == ‘http://www.wrox.com‘){
        //處理接收到的數據
        processMessage(event.data);
        
        //可選:向來源窗口發送回執
        event.source.postMessage("Received!","http://p2p.wrox.com");
    }
},false);

XDM還有一些怪異之處。postMessage()的第一個參數最早是作為“永遠都是字符串來實現的”,但後來改變了可以使用任意結構了。並非所有瀏覽器都支持任意結構,所以最好還是傳入字符串,即在要傳遞數據之前調用JSON.stringify()方法,然後在onmessage事件處理程序中調用JSON.parse()。

原生拖放

拖動事件

拖動某元素時,將依次觸發下列事件:

  • (1)dragstart
  • (2)drag
  • (3)dragend

上述三個事件的目標都是被拖動的元素。

當某個元素被拖動到一個有效的放置目標上時,下列事件會依次執行:

(1)dragenter

(2)dragover

(2)dragleave或drop

只要有元素被拖動到放置目標上,就會觸發dragenter事件(類似於mouseover事件)。緊隨其後的是dragover事件,而且在被拖動的元素還在放置目標的範圍內移動時,就會持續觸發該事件。如果元素被拖出了放置目標,dragover事件就不再發生,但會觸發dragleave事件(類似於mouseout事件)。如果元素被放到了放置目標中,則會觸發drop事件而不是dragleave事件。上述三個事件的目標都是作為放置目標的元素。

自定義放置目標

在拖動元素經過某些無效放置目標時,可以看到一種特殊的光標(圓環中有一條反斜線),表示不能放置。雖然所有元素都支持放置目標事件,但這些元素默認是不允許放置的。如果拖動元素經過不允許放置的元素,無論用戶如果操作,都不會發生drop事件。不過,你可以把任何元素變成有效的放置目標,方法是重寫dragenter和dragover事件的默認行為。例如,假設有一個ID為“droptarget”的<div>元素,可以用如下代碼將它變成一個放置目標。

var droptarget = document.getElementById("droptarget");
EventUtil.addHandler(droptarget,"dragover",function(){
    EventUtil.preventDefault(event);
});
EventUtil.addHandler(droptarget,"dragenter",function(){
    EventUtil.preventDefault(event);

以上代碼執行後,你就會發現當拖動著元素移動到放置目標上時,光標變成了允許放置的符號。當然,釋放鼠標也會觸發drop事件。

在Firefox3.5中,放置事件的默認行為是打開被放到放置目標上的URL。換句話說,如果是把圖像拖動到放置目標上,頁面就會轉向圖像文件;而如果是把文本拖放到放置目標上,則會導致無效URL錯誤。因此,為了讓Firefox支持正常的拖放,還要取消drop事件的默認行為,阻止它打開URL:

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

dataTransfer對象

dataTransfer對象是事件對象的一個屬性,用於從被拖動元素向放置目標傳遞字符串格式的數據。因為他是事件對象的屬性,所以只能在拖動事件的事件處理程序中訪問dataTransfer對象。

dataTransfer對象有兩個主要的方法:getData()和setData()。getData()可以取得由setData()保存的值。setData()方法的第一個參數,也是getData()方法唯一的一個參數,是一個字符串,表示保存的數據類型,取值為“text”或“URL”,如下代碼:

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

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

IE只定義了“text”和“URL”兩種有效的數據類型,而HTML5則對此加以擴展,允許指定各種MIME類型。考慮到向後兼容,HTML5也支持“text”和“URL”,但這兩種類型會被映射為“text/plain”和“text/url-list”。

實際上,dataTransfer對象可以為每種MIME類型都保存一個值。換句話說,同時在這個對象中保存一段文本和一個URL不會有任何問題。不過,保存在dataTransfer對象的數據只能在drop事件處理程序中讀取。如果在ondrop處理程序中沒有讀到數據,那就是dataTransfer對象已經被被銷毀了,數據也丟失了。

Firfox在其第五個版本之前不能將"URL"和“text”映射為“text/url-list”和“text/plain”,但卻能把“Text”映射為“text/plain”,為了更好的兼容瀏覽器,可使用如下代碼:

var dataTransfer = event.dataTransfer;
//讀取URL 
var url = dataTransfer.getData(‘url‘) || dataTransfer.getData("text/url-list");
//讀取文本
var text = dataTransfer.getData("Text");

註意:一定要把短數據類型放到前面,因為IE10以及之前的版本不支持擴展的MIME類型,而他們在遇到無法識別的數據類型時,會拋出錯誤。

dropEffect和effectAllowed

其中,通過dropEffect屬性可以知道被拖動的元素能夠執行哪種放置行為。這個屬性有4個可能的值。

  • none:不能把拖動的元素放在這裏。這是除文本框之外所有元素的默認值。
  • move:應該把拖動的元素移動到放置目標。
  • copy:應該把拖動的元素復制到放置目標。
  • link:表示放置目標會打開拖動的元素(但拖動的元素必須是一個鏈接,有URL)。

要使用dropEffect屬性,必須在ondragenter事件處理程序中針對放置目標來設置它。

dropEffect屬性只有搭配effectAllowed屬性才有用。effectAllowed屬性表示允許拖動元素的哪種dropEffect。effectAllowed屬性有以下可能的值:

  • uninitialized:沒有給被拖動的元素設置任何放置行為。
  • none:被拖動的元素不能有任何行為。
  • copy:只允許值為“copy”的dropEffect。
  • link:只允許值為“link”的dropEffect。
  • move:只允許值為“move”的dropEffect。
  • copyLink:只允許值為“copy”和“link”的dropEffect。
  • copyMove:只允許值為“copy”和“move”的dropEffect。
  • linkMove:只允許值為“link”和“move”的dropEffect。
  • all:允許任意的dropEffect。

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

可拖動

默認情況下,圖像、鏈接、文本是可以拖動的,文本只有在被選中的情況下才能拖動,而圖像和鏈接在任何時候都可以拖動。

讓其它元素可以拖動,HTML5為所有的HTML元素規定了一個draggable屬性。

<!--讓圖像不可拖動-->
<img src="images/avatar.png" draggable="false"/>

<!--讓這個元素可以拖動-->
<div draggable="true">可拖動的元素</div>

其它成員

HTML5規範規定dataTransfer對象還有下列屬性和方法:

  • addElement(element):為拖動操作添加一個元素。添加這個元素只影響數據(即增加作為拖動源而響應回調的對象),不會影響拖動操作時頁面元素的外觀。
  • clearData(format):清除以特定格式保存的數據。
  • setDragImage(element,x,y):指定一副圖像,當拖動發生時,顯示在光標下方。這個方法接收的三個參數分別為要顯示的HTML元素和光標在圖像中的x、y坐標。其中,HTML元素可以是一副圖像,也可以是其它元素。
  • types:當前保存的數據類型。這是一個類似數組的集合,以“text”這樣的字符串形式保存著數據類型。

媒體元素

<audio>和<video>

《JavaScript高級程序設計》筆記:HTML5腳本編程(16)