一、 跨文檔消息傳遞
跨文檔消息傳送(cross-document messaging
),有時候簡稱為XDM
,指的是在來自不同域的頁面間傳遞消息。
XDM
的核心是postMessage()
方法,向另一個地方(包含在當(dāng)前頁面中的<iframe>
元素,或者由當(dāng)前頁面彈出的窗口。)傳遞數(shù)據(jù)。
otherWindow.postMessage(message, targetOrigin, [transfer]);
-
otherWindow
:其他窗口的一個引用,比如iframe
的contentWindow
屬性、執(zhí)行window.open
返回的窗口對象、或者是命名過或數(shù)值索引的window.frames
。
message
: 將要發(fā)送到其他window
的數(shù)據(jù)。它將會被結(jié)構(gòu)化克隆算法序列化。這意味著你可以不受什么限制的將數(shù)據(jù)對象安全的傳送給目標(biāo)窗口而無需自己序列化。targetOrigin
:通過窗口的origin
屬性來指定哪些窗口能接收到消息事件,其值可以是字符串"*"
(表示無限制,不建議使用)或者一個URI
。如果目標(biāo)窗口的協(xié)議、主機(jī)地址或端口這三者的任意一項不匹配targetOrigin
提供的值,那么消息就不會被發(fā)送;只有三者完全匹配,消息才會被發(fā)送。這個機(jī)制用來控制消息可以發(fā)送到哪些窗口(非常重要);transfer
[可選]:是一串和message
同時傳遞的Transferable
對象. 這些對象的所有權(quán)將被轉(zhuǎn)移給消息的接收方,而發(fā)送一方將不再保有所有權(quán)。
接收到XDM
消息時,會觸發(fā)window
對象的message
事件。這個事件是以異步形式觸發(fā)的,因此從發(fā)送消息到接收消息(觸發(fā)接收窗口的message
事件)可能要經(jīng)過一段時間的延遲。觸發(fā)message
事件后,傳遞給onmessage
處理程序的事件對象包含以下三方面的重要信息。
-
data
:從其他window
中傳遞過來的對象。 -
origin
:調(diào)用postMessage
時消息發(fā)送方窗口的origin
. 這個字符串由 協(xié)議、域名、端口號拼接而成。端口號(443
為https
的默認(rèn)值) -
source
:對發(fā)送消息的窗口對象的引用; 可以使用此來在具有不同origin
的兩個窗口之間建立雙向通信。
安全相關(guān):如果您不希望從其他網(wǎng)站接收message
,請不要為message
事件添加任何事件偵聽器。 這是一個完全萬無一失的方式來避免安全問題;如果您確實希望從其他網(wǎng)站接收message
,請始終使用origin
和source
屬性驗證發(fā)件人的身份。 當(dāng)您使用postMessage
將數(shù)據(jù)發(fā)送到其他窗口時,始終指定精確的目標(biāo)origin
,而不是"*"
。
// 示例:
// 主窗口域名是<http://example.com:8080> 傳遞"i am main" 給彈出頁
// 彈出頁域名是<http://example.org> 傳遞"i am pop"給主窗口
// 主窗口 JS
var popup = window.open('http://example.org','pop')
// 參數(shù)是(url,新窗口名稱) 不是title 而是可以用來作為超鏈接 <a> 或表單 <form> 元素的目標(biāo)屬性值。字符串中不能含有空白字符。
popup.postMessage("i am main", "http://example.org");
// 發(fā)送-> 傳遞消息給彈出頁 第二個參數(shù)必須精準(zhǔn)匹配
// 接收-> 定義事件處理程序處理接收到的消息
function receiveMessage(event){
// 必須使用判斷 以保證安全 網(wǎng)站不被攻擊
if (event.origin !== "http://example.org"){
return;
}else{
// do something
}
// event.source 是我們通過window.open打開的彈出頁面 popup
// event.data 是 popup發(fā)送給當(dāng)前頁面的消息
}
window.addEventListener("message",receiveMessage,false)
// 彈出頁 JS
function popReceiveMessage(event){
if (event.origin !== "http://example.com:8080"){
return;
}else{
// 向來源窗口發(fā)送回執(zhí)
event.source.postMessage("i am pop" +event.origin);
}
}
window.addEventListener("message", popReceiveMessage, false);
二、拖放
拖放事件
- 發(fā)生在被拖放的元素上。
-
dragstart
:按下鼠標(biāo)鍵并開始移動鼠標(biāo)時觸發(fā)。 -
drag
:在元素被拖動期間會持續(xù)觸發(fā)該事件 -
dragend
:當(dāng)拖動停止時觸發(fā)(無論是否將元素放到了有效目標(biāo))
-
- 發(fā)生在放置目標(biāo)上。
-
dragenter
:有元素被拖入時觸發(fā)。 -
dragover
:被拖動元素在放置目標(biāo)內(nèi)部移動時觸發(fā)。 -
dragleave
:被拖動元素被拖出放置目標(biāo)后觸發(fā)。(進(jìn)來之后出去) -
drop
:元素被放到了放置目標(biāo)中時觸發(fā)。
-
如果拖動元素經(jīng)過不允許放置的元素,無論用戶如何操作,都不會發(fā)生drop
事件。不過,你可以把任何元素變成有效的放置目標(biāo),方法是阻止dragenter
和dragover
事件的默認(rèn)行為。你就會發(fā)現(xiàn)當(dāng)拖動著元素移動到放置目標(biāo)上時,光標(biāo)變成了允許放置的符號。當(dāng)然,釋放鼠標(biāo)也會觸發(fā)drop
事件。
在Firefox 3.5+
中,放置事件的默認(rèn)行為是打開被放到放置目標(biāo)上的URL
(被放入元素是圖片則頁面轉(zhuǎn)向圖像文件,如果是文本,則導(dǎo)致錯誤,無效的URL
),如果想正常處理放置事件,也需要阻止drop
事件打開URL
的行為
dataTransfer
對象
它是事件對象的一個屬性,用于從被拖動元素向放置目標(biāo)傳遞字符串格式的數(shù)據(jù)。只能在拖放事件的事件處理程序中訪問dataTransfer
對象。有兩個主要方法:getData()
和setData()
//設(shè)置和接收文本數(shù)據(jù)
event.dataTransfer.setData("text", "some text");
var text = event.dataTransfer.getData("text");
//設(shè)置和接收URL
event.dataTransfer.setData("URL", "http://www.wrox.com/");
var url = event.dataTransfer.getData("URL");
IE
只定義了"text"
和"URL"
兩種有效的數(shù)據(jù)類型,而HTML5
則對此加以擴(kuò)展,允許指定各種MIME
類型。考慮到向后兼容,HTML5
也支持"text"
和"URL"
,但這兩種類型會被映射為"text/plain"
和"text/uri-list"
。
保存在dataTransfer
對象中的數(shù)據(jù)只能在drop
事件處理程序中讀取。如果在ondrop
處理程序中沒有讀到數(shù)據(jù),那就是dataTransfer
對象已經(jīng)被銷毀,數(shù)據(jù)也丟失了。
在拖動文本框中的文本或鏈接、圖像時,瀏覽器會調(diào)用setData()
方法以"text"
或"URL"
保存,然后,在這些元素被拖放到放置目標(biāo)時,就可以通過getData()
讀到這些數(shù)據(jù)。當(dāng)然,作為開發(fā)人員,你也可以在dragstart
事件處理程序中調(diào)用setData()
,手工保存自己要傳輸?shù)臄?shù)據(jù),以便將來使用。如果將數(shù)據(jù)保存為URL
,瀏覽器會將其當(dāng)成網(wǎng)頁中的鏈接。換句話說,如果你把它放置到另一個瀏覽器窗口中,瀏覽器就會打開該URL
。
// 兼容Firefox5之前 不能正確映射"text"和"url" 只能把"Text"(T 大寫)映射為"text/plain"。
var dataTransfer = event.dataTransfer;
//讀取URL
var url = dataTransfer.getData("url") ||dataTransfer.getData("text/uri-list");
//讀取文本
var text = dataTransfer.getData("Text");
dataTransfer
對象的兩個屬性 dropEffect
與effectAllowed
-
dropEffect
屬性可以知道被拖動的元素能夠執(zhí)行哪種放置行為-
"none"
:不能把拖動的元素放在這里。這是除文本框之外所有元素的默認(rèn)值。 -
"move"
:應(yīng)該把拖動的元素移動到放置目標(biāo)。 -
"copy"
:應(yīng)該把拖動的元素復(fù)制到放置目標(biāo)。 -
"link"
:表示放置目標(biāo)會打開拖動的元素(但拖動的元素必須是一個鏈接,有URL
)。
-
使用dropEffect
屬性,必須在ondragenter
事件處理程序中針對放置目標(biāo)來設(shè)置它。在把元素拖動到放置目標(biāo)上時,以上每一個值都會導(dǎo)致光標(biāo)顯示為不同的符號。然而,瀏覽器只能幫你改變光標(biāo)的樣式,而其他的都要靠你自己來實現(xiàn)。
dropEffect
屬性只有搭配effectAllowed
屬性才有用。effectAllowed
屬性表示允許拖動元素的哪種dropEffect
,必須在ondragstart
事件處理程序中設(shè)置effectAllowed
屬性,定義此次拖動可以允許哪些操作,而當(dāng)ondragenter
觸發(fā)時,針對放置目標(biāo)來設(shè)置dropEffect
屬性來進(jìn)行該操作。
-
effectAllowed
屬性表示允許拖動元素的哪種dropEffect
-
"uninitialized"
:沒有給被拖動的元素設(shè)置任何放置行為。 -
"none"
:被拖動的元素不能有任何行為。s -
"copy"
:只允許值為"copy"
的dropEffect
。 -
"link"
:只允許值為"link"
的dropEffect
。 -
"move"
:只允許值為"move"
的dropEffect
。 -
"copyLink"
:允許值為"copy"
和"link"
的dropEffect
。 -
"copyMove"
:允許值為"copy"
和"move"
的dropEffect
。 -
"linkMove"
:允許值為"link"
和"move"
的dropEffect
。 -
"all"
:允許任意dropEffect
-
draggable
可拖動
文本在被選中的情況下才能拖動,而圖像和鏈接在任何時候都可以拖動。HTML5
為所有HTML
元素規(guī)定了一個draggable
屬性,表示元素是否可以拖動。圖像和鏈接的draggable
屬性自動被設(shè)置成了true
,而其他元素這個屬性的默認(rèn)值都是false
。要想讓其他元素可拖動,或者讓圖像或鏈接不能拖動,都可以設(shè)置這個屬性。
其他成員
dataTransfer
對象還應(yīng)該包含下列方法和屬性
-
addElement(element)
:為拖動操作添加一個元素。添加這個元素只影響數(shù)據(jù)(即增加作為拖動源而響應(yīng)回調(diào)的對象),不會影響拖動操作時頁面元素的外觀。部分瀏覽器支持 -
clearData(format)
:清除以特定格式保存的數(shù)據(jù)。實現(xiàn)這個方法的瀏覽器有IE
、Fireforx 3.5+
、Chrome
和Safari 4+
。 -
setDragImage(element, x, y)
:指定一幅圖像,當(dāng)拖動發(fā)生時,顯示在光標(biāo)下方。這個方法接收的三個參數(shù)分別是要顯示的HTML
元素和光標(biāo)在圖像中的x、y
坐標(biāo)。其中,HTML
元素可以是一幅圖像,也可以是其他元素。是圖像則顯示圖像,是其他元素則顯示渲染后的元素。實現(xiàn)這個方法的瀏覽器有Firefox 3.5+
、Safari 4+
和Chrome
。 -
types
:當(dāng)前保存的數(shù)據(jù)類型。這是一個類似數(shù)組的集合,以"text"這樣的字符串形式保存著數(shù)據(jù)類型。實現(xiàn)這個屬性的瀏覽器有IE10+
、Firefox 3.5+
和Chrome
。
三、媒體元素
<audio>
和<video>
位于開始和結(jié)束標(biāo)簽之間的任何內(nèi)容都將作為后備內(nèi)容,在瀏覽器不支持這兩個媒體元素的情況下顯示。因為并非所有瀏覽器都支持所有媒體格式,所以可以指定多個不同的媒體來源。為此,不用在標(biāo)簽中指定src
屬性,而是要像下面這樣使用一或多個<source>
元素。
<!-- 嵌入視頻 -->
<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>
通過這些屬性可以知道媒體的當(dāng)前狀態(tài)。:
-
src
:指向要加載的媒體文件。 -
width
和height
:指定視頻播放器的大小 -
poster
:屬性指定圖像的URI
可以在加載視頻內(nèi)容期間顯示一幅圖像。(封面) -
controls
:布爾值,瀏覽器是否顯示UI 控件,以便用戶直接操作媒體 -
autoplay
: 布爾值 取得或設(shè)置autoplay
標(biāo)志 -
buffered
:時間范圍 表示已下載的緩沖的時間范圍的對象 -
bufferedBytes
: 字節(jié)范圍 表示已下載的緩沖的字節(jié)范圍的對象 -
bufferingRate
: 整數(shù) 下載過程中每秒鐘平均接收到的位數(shù) -
bufferingThrottled
: 布爾值 表示瀏覽器是否對緩沖進(jìn)行了節(jié)流 -
currentLoop
: 整數(shù) 媒體文件已經(jīng)循環(huán)的次數(shù) -
currentSrc
:字符串 當(dāng)前播放的媒體文件的URL -
currentTime
: 浮點數(shù) 已經(jīng)播放的秒數(shù) -
defaultPlaybackRate
:浮點數(shù) 取得或設(shè)置默認(rèn)的播放速度。默認(rèn)值為1.0秒 -
duration
:浮點數(shù) 媒體的總播放時間(秒數(shù)) -
ended
: 布爾值 表示媒體文件是否播放完成 -
loop
: 布爾值 取得或設(shè)置媒體文件在播放完成后是否再從頭開始播放 -
muted
: 布爾值 取得或設(shè)置媒體文件是否靜音 -
networkState
: 整數(shù) 表示當(dāng)前媒體的網(wǎng)絡(luò)連接狀態(tài):0
表示空,1
表示正在加載,2
表示正在加載元數(shù)據(jù),3
表示已經(jīng)加載了第一幀,4
表示加載完成 -
paused
: 布爾值 表示播放器是否暫停 -
playbackRate
: 浮點數(shù) 取得或設(shè)置當(dāng)前的播放速度。用戶可以改變這個值,讓媒體播放速度變快或變慢,這與只能由開發(fā)人員修改的defaultPlaybackRate
不同 -
played
: 時間范圍 到目前為止已經(jīng)播放的時間范圍 -
readyState
:整數(shù) 表示媒體是否已經(jīng)就緒(可以播放了)。0
表示數(shù)據(jù)不可用,1
表示可以顯示當(dāng)前幀,2
表示可以開始播放,3
表示媒體可以從頭到尾播放 -
seekable
: 時間范圍 可以搜索的時間范圍 -
seeking
: 布爾值 表示播放器是否正移動到媒體文件中的新位置 -
start
:浮點數(shù) 取得或設(shè)置媒體文件中開始播放的位置,以秒表示 -
totalBytes
: 整數(shù) 當(dāng)前資源所需的總字節(jié)數(shù) -
videoHeight
: 整數(shù) 返回視頻(不一定是元素)的高度。只適用于<video>
-
videoWidth
: 整數(shù) 返回視頻(不一定是元素)的寬度。只適用于<video>
-
volume
:浮點數(shù) 取得或設(shè)置當(dāng)前音量,值為0.0到1.0
事件有:
-
abort
下載中斷 -
canplay
可以播放時;readyState
值為2 -
canplaythrough
: 播放可繼續(xù),而且應(yīng)該不會中斷;readyState
值為3 -
canshowcurrentframe
:當(dāng)前幀已經(jīng)下載完成;readyState
值為1 -
dataunavailable
:因為沒有數(shù)據(jù)而不能播放;readyState
值為0 -
durationchange
:duration
屬性的值改變 -
emptied
:網(wǎng)絡(luò)連接關(guān)閉 -
empty
:發(fā)生錯誤阻止了媒體下載 -
ended
:媒體已播放到末尾,播放停止 -
error
:下載期間發(fā)生網(wǎng)絡(luò)錯誤 -
load
: 所有媒體已加載完成。這個事件可能會被廢棄,建議使用canplaythrough
-
loadeddata
:媒體的第一幀已加載完成 -
loadedmetadata
: 媒體的元數(shù)據(jù)已加載完成 -
loadstart
:下載已開始 -
pause
: 播放已暫停 -
play
: 媒體已接收到指令開始播放 -
playing
: 媒體已實際開始播放 -
progress
: 正在下載 -
ratechange
: 播放媒體的速度改變 -
seeked
:搜索結(jié)束 -
seeking
:正移動到新位置 -
stalled
瀏覽器嘗試下載,但未接收到數(shù)據(jù) -
timeupdate
:currentTime
被以不合理或意外的方式更新 -
volumechange
:volume
屬性值或muted
屬性值已改變 -
waiting
: 播放暫停,等待下載更多數(shù)據(jù)
//取得元素的引用
var player = document.getElementById("player"),
btn = document.getElementById("video-btn"),
curtime = document.getElementById("curtime"),
duration = document.getElementById("duration");
//更新播放時間
duration.innerHTML = player.duration;
//為按鈕添加事件處理程序
EventUtil.addHandler(btn, "click", function(event){
if (player.paused){
player.play(); // play方法 播放
btn.value = "Pause";
} else {
player.pause(); // pause方法 暫停
btn.value = "Play";
}
});
//定時更新當(dāng)前時間 以小于1000ms觸發(fā)
setInterval(function(){
curtime.innerHTML = player.currentTime;
}, 250);
檢測編解碼器的支持情況
canPlayType()
方法,該方法接收一種格式/編解碼器字符串,返回probably"
、"maybe"
或" "
,如果給canPlayType()
傳入了一種MIME
類型(期望接受的是編碼格式字符串),則返回值很可能是"maybe"
或空字符串。這是因為媒體文件本身只不過是音頻或視頻的一個容器,而真正決定文件能否播放的還是編碼的格式。在同時傳入MIME
類型和編解碼器的情況下,可能性就會增加,返回的字符串會變成"probably"
。
var audio = document.getElementById("audio-player");
//很可能"maybe"
if (audio.canPlayType("audio/mpeg")){ // MIME
//進(jìn)一步處理
}
//可能是"probably"
if (audio.canPlayType("audio/ogg; codecs=\"vorbis\"")){ // MIME & 編碼格式
//進(jìn)一步處理
}
常用音頻的音頻格式和編解碼器
-
AAC
:audio/mp4; codecs="mp4a.40.2"
,瀏覽器支持的有IE9+
、Safari 4+
、iOS版Safari
-
MP3
:audio/mpeg
,瀏覽器支持的有IE9+
、Chrome
-
Vorbis
:audio/ogg; codecs="vorbis"
,瀏覽器支持的有Firefox 3.5+
、Chrome
、Opera 10.5+
-
WAV
:audio/wav; codecs="1"
,瀏覽器支持的有Firefox 3.5+
、Opera 10.5+
、Chrome
常用視頻的視頻格式和編解碼器
-
H.264
:video/mp4; codecs="avc1.42E01E, mp4a.40.2"
,瀏覽器支持的有IE9+
、Safari 4+
、iOS版Safari
、Android版WebKit
-
Theora
:video/ogg; codecs="theora"
,瀏覽器支持的有Firefox 3.5+
、Opera 10.5
、Chrome
-
WebM
:video/webm; codecs="vp8, vorbis"
,瀏覽器支持的有Firefox 4+
、Opera 10.6
、Chrome
Audio
類型
<audio>
元素還有一個原生的JavaScript
構(gòu)造函數(shù)Audio
,可以在任何時候播放音頻。從同為DOM
元素的角度看,Audio
與Image
很相似,但Audio
不用像Image
那樣必須插入到文檔中。只要創(chuàng)建一個新實例,并傳入音頻源文件即可。
var audio = new Audio("sound.mp3");
EventUtil.addHandler(audio, "canplaythrough", function(event){
audio.play();
})
// 創(chuàng)建實例即可開始下載指定的文件。下載完成后,調(diào)用play()就可以播放音頻。
在iOS
中,調(diào)用play()
時會彈出一個對話框,得到用戶的許可后才能播放聲音。如果想在一段音頻播放后再播放另一段音頻,必須在onfinish
事件處理程序中調(diào)用play()
方法。
四、歷史狀態(tài)管理
history.pushState()
通過狀態(tài)管理API
, 能夠在不加載新頁面的情況下改變?yōu)g覽器的URL
。為此, 需要使用history.pushState()
方法,該方法可以接收三個參數(shù):狀態(tài)對象、新狀態(tài)的標(biāo)題和新URL
新URL
不必須為絕對路徑。如果新URL
是相對路徑,那么它將被作為相對于當(dāng)前URL
處理。新URL
必須與當(dāng)前URL
同源,否則 pushState()
會拋出一個異常。該參數(shù)是可選的,缺省為當(dāng)前URL
。
// 假設(shè)在 http://mozilla.org/foo.html 中執(zhí)行了以下 JS 代碼:
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
// 第二個參數(shù)沒有瀏覽器實現(xiàn),可以傳空字符串 或者一個短標(biāo)題(安全的選擇)。
// 這將使瀏覽器地址欄顯示為 http://mozilla.org/bar.html
// 但并不會導(dǎo)致瀏覽器加載 bar.html ,甚至不會檢查bar.html 是否存在。
執(zhí)行pushState()
方法后,新的狀態(tài)信息就會被加入歷史狀態(tài)棧,而瀏覽器地址欄也會變成新的相對URL
。狀態(tài)改變之后查詢location.href
也會返回與地址欄中相同的地址,但是瀏覽器并不會真的向服務(wù)器發(fā)送請求。
假設(shè)現(xiàn)在用戶又訪問了 http://google.com
,然后點擊了返回按鈕。此時,地址欄將顯示 http://mozilla.org/bar.html
,同時頁面會觸發(fā) popstate
事件,事件對象state
中包含了 stateObj
的一份拷貝。頁面本身與 foo.html
一樣,盡管其在 popstate
事件中可能會修改自身的內(nèi)容。
如果我們再次點擊返回按鈕,頁面URL
會變?yōu)?code>http://mozilla.org/foo.html,文檔對象document
會觸發(fā)另外一個 popstate
事件,這一次的事件對象state object
為null
。 這里也一樣,返回并不改變文檔的內(nèi)容,盡管文檔在接收 popstate
事件時可能會改變自己的內(nèi)容,其內(nèi)容仍與之前的展現(xiàn)一致。
EventUtil.addHandler(window, "popstate", function(event){
var state = event.state;
if (state){ //第一個頁面加載時state 為空
// 進(jìn)一步操作
}
})
history.replaceState()
history.replaceState()
與history.pushState()
非常相似,區(qū)別在于 replaceState()
是修改(替換)了當(dāng)前的歷史棧棧頂?shù)臓顟B(tài)信息,而不是新增。 注意這并不會阻止其在全局瀏覽器歷史記錄中創(chuàng)建一個新的歷史記錄項。
AURL
push到 BURL
,再push到CURL
,后退會后退到BURL
;
AURL
push到 BURL
,再replace到 CURL
,后退會后退到AURL
;
popstate
事件
每當(dāng)活動的歷史記錄項發(fā)生變化時, popstate
事件都會被傳遞給window
對象。如果當(dāng)前活動的歷史記錄項是被 pushState
創(chuàng)建的,或者是由 replaceState
改變的,那么 popstate
事件的狀態(tài)屬性 state
會包含一個當(dāng)前歷史記錄狀態(tài)對象的拷貝(調(diào)用這兩個方法的第一個參數(shù))
頁面加載時,或許會有個非null
的狀態(tài)對象。這是有可能發(fā)生的,舉個例子,假如頁面(通過pushState()
或replaceState()
方法)設(shè)置了狀態(tài)對象而后用戶重啟了瀏覽器。那么當(dāng)頁面重新加載時,頁面會接收一個onload
事件,但沒有popstate
事件,但是此時訪問history.state
屬性會得到如同popstate
被觸發(fā)時能得到的狀態(tài)對象。