一、 跨文档消息传递
跨文档消息传送(cross-document messaging
),有时候简称为XDM
,指的是在来自不同域的页面间传递消息。
XDM
的核心是postMessage()
方法,向另一个地方(包含在当前页面中的元素,或者由当前页面弹出的窗口。)传递数据。
otherWindow.postMessage(message, targetOrigin, [transfer]);
-
otherWindow
:其他窗口的一个引用,比如iframe
的contentWindow
属性、执行window.open
返回的窗口对象、或者是命名过或数值索引的window.frames
。
message
: 将要发送到其他window
的数据。它将会被结构化克隆算法序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。targetOrigin
:通过窗口的origin
属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"
(表示无限制,不建议使用)或者一个URI
。如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin
提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口(非常重要);transfer
[可选]:是一串和message
同时传递的Transferable
对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
接收到XDM
消息时,会触发window
对象的message
事件。这个事件是以异步形式触发的,因此从发送消息到接收消息(触发接收窗口的message
事件)可能要经过一段时间的延迟。触发message
事件后,传递给onmessage
处理程序的事件对象包含以下三方面的重要信息。
-
data
:从其他window
中传递过来的对象。 -
origin
:调用postMessage
时消息发送方窗口的origin
. 这个字符串由 协议、域名、端口号拼接而成。端口号(443
为https
的默认值) -
source
:对发送消息的窗口对象的引用; 可以使用此来在具有不同origin
的两个窗口之间建立双向通信。
安全相关:如果您不希望从其他网站接收message
,请不要为message
事件添加任何事件侦听器。 这是一个完全万无一失的方式来避免安全问题;如果您确实希望从其他网站接收message
,请始终使用origin
和source
属性验证发件人的身份。 当您使用postMessage
将数据发送到其他窗口时,始终指定精确的目标origin
,而不是"*"
。
// 示例:
// 主窗口域名是 传递"i am main" 给弹出页
// 弹出页域名是 传递"i am pop"给主窗口
// 主窗口 JS
var popup = window.open('http://example.org','pop')
// 参数是(url,新窗口名称) 不是title 而是可以用来作为超链接 或表单
// 弹出页 JS
function popReceiveMessage(event){
if (event.origin !== "http://example.com:8080"){
return;
}else{
// 向来源窗口发送回执
event.source.postMessage("i am pop" +event.origin);
}
}
window.addEventListener("message", popReceiveMessage, false);
二、拖放
拖放事件
- 发生在被拖放的元素上。
-
dragstart
:按下鼠标键并开始移动鼠标时触发。 -
drag
:在元素被拖动期间会持续触发该事件 -
dragend
:当拖动停止时触发(无论是否将元素放到了有效目标)
-
- 发生在放置目标上。
-
dragenter
:有元素被拖入时触发。 -
dragover
:被拖动元素在放置目标内部移动时触发。 -
dragleave
:被拖动元素被拖出放置目标后触发。(进来之后出去) -
drop
:元素被放到了放置目标中时触发。
-
如果拖动元素经过不允许放置的元素,无论用户如何操作,都不会发生drop
事件。不过,你可以把任何元素变成有效的放置目标,方法是阻止dragenter
和dragover
事件的默认行为。你就会发现当拖动着元素移动到放置目标上时,光标变成了允许放置的符号。当然,释放鼠标也会触发drop
事件。
在Firefox 3.5+
中,放置事件的默认行为是打开被放到放置目标上的URL
(被放入元素是图片则页面转向图像文件,如果是文本,则导致错误,无效的URL
),如果想正常处理放置事件,也需要阻止drop
事件打开URL
的行为
dataTransfer
对象
它是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据。只能在拖放事件的事件处理程序中访问dataTransfer
对象。有两个主要方法:getData()
和setData()
//设置和接收文本数据
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/uri-list"
。
保存在dataTransfer
对象中的数据只能在drop
事件处理程序中读取。如果在ondrop
处理程序中没有读到数据,那就是dataTransfer
对象已经被销毁,数据也丢失了。
在拖动文本框中的文本或链接、图像时,浏览器会调用setData()
方法以"text"
或"URL"
保存,然后,在这些元素被拖放到放置目标时,就可以通过getData()
读到这些数据。当然,作为开发人员,你也可以在dragstart
事件处理程序中调用setData()
,手工保存自己要传输的数据,以便将来使用。如果将数据保存为URL
,浏览器会将其当成网页中的链接。换句话说,如果你把它放置到另一个浏览器窗口中,浏览器就会打开该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
属性可以知道被拖动的元素能够执行哪种放置行为-
"none"
:不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值。 -
"move"
:应该把拖动的元素移动到放置目标。 -
"copy"
:应该把拖动的元素复制到放置目标。 -
"link"
:表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL
)。
-
使用dropEffect
属性,必须在ondragenter
事件处理程序中针对放置目标来设置它。在把元素拖动到放置目标上时,以上每一个值都会导致光标显示为不同的符号。然而,浏览器只能帮你改变光标的样式,而其他的都要靠你自己来实现。
dropEffect
属性只有搭配effectAllowed
属性才有用。effectAllowed
属性表示允许拖动元素的哪种dropEffect
,必须在ondragstart
事件处理程序中设置effectAllowed
属性,定义此次拖动可以允许哪些操作,而当ondragenter
触发时,针对放置目标来设置dropEffect
属性来进行该操作。
-
effectAllowed
属性表示允许拖动元素的哪种dropEffect
-
"uninitialized"
:没有给被拖动的元素设置任何放置行为。 -
"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
元素规定了一个draggable
属性,表示元素是否可以拖动。图像和链接的draggable
属性自动被设置成了true
,而其他元素这个属性的默认值都是false
。要想让其他元素可拖动,或者让图像或链接不能拖动,都可以设置这个属性。
其他成员
dataTransfer
对象还应该包含下列方法和属性
-
addElement(element)
:为拖动操作添加一个元素。添加这个元素只影响数据(即增加作为拖动源而响应回调的对象),不会影响拖动操作时页面元素的外观。部分浏览器支持 -
clearData(format)
:清除以特定格式保存的数据。实现这个方法的浏览器有IE
、Fireforx 3.5+
、Chrome
和Safari 4+
。 -
setDragImage(element, x, y)
:指定一幅图像,当拖动发生时,显示在光标下方。这个方法接收的三个参数分别是要显示的HTML
元素和光标在图像中的x、y
坐标。其中,HTML
元素可以是一幅图像,也可以是其他元素。是图像则显示图像,是其他元素则显示渲染后的元素。实现这个方法的浏览器有Firefox 3.5+
、Safari 4+
和Chrome
。 -
types
:当前保存的数据类型。这是一个类似数组的集合,以"text"这样的字符串形式保存着数据类型。实现这个属性的浏览器有IE10+
、Firefox 3.5+
和Chrome
。
三、媒体元素
和
位于开始和结束标签之间的任何内容都将作为后备内容,在浏览器不支持这两个媒体元素的情况下显示。因为并非所有浏览器都支持所有媒体格式,所以可以指定多个不同的媒体来源。为此,不用在标签中指定src
属性,而是要像下面这样使用一或多个元素。
通过这些属性可以知道媒体的当前状态。:
-
src
:指向要加载的媒体文件。 -
width
和height
:指定视频播放器的大小 -
poster
:属性指定图像的URI
可以在加载视频内容期间显示一幅图像。(封面) -
controls
:布尔值,浏览器是否显示UI 控件,以便用户直接操作媒体 -
autoplay
: 布尔值 取得或设置autoplay
标志 -
buffered
:时间范围 表示已下载的缓冲的时间范围的对象 -
bufferedBytes
: 字节范围 表示已下载的缓冲的字节范围的对象 -
bufferingRate
: 整数 下载过程中每秒钟平均接收到的位数 -
bufferingThrottled
: 布尔值 表示浏览器是否对缓冲进行了节流 -
currentLoop
: 整数 媒体文件已经循环的次数 -
currentSrc
:字符串 当前播放的媒体文件的URL -
currentTime
: 浮点数 已经播放的秒数 -
defaultPlaybackRate
:浮点数 取得或设置默认的播放速度。默认值为1.0秒 -
duration
:浮点数 媒体的总播放时间(秒数) -
ended
: 布尔值 表示媒体文件是否播放完成 -
loop
: 布尔值 取得或设置媒体文件在播放完成后是否再从头开始播放 -
muted
: 布尔值 取得或设置媒体文件是否静音 -
networkState
: 整数 表示当前媒体的网络连接状态:0
表示空,1
表示正在加载,2
表示正在加载元数据,3
表示已经加载了第一帧,4
表示加载完成 -
paused
: 布尔值 表示播放器是否暂停 -
playbackRate
: 浮点数 取得或设置当前的播放速度。用户可以改变这个值,让媒体播放速度变快或变慢,这与只能由开发人员修改的defaultPlaybackRate
不同 -
played
: 时间范围 到目前为止已经播放的时间范围 -
readyState
:整数 表示媒体是否已经就绪(可以播放了)。0
表示数据不可用,1
表示可以显示当前帧,2
表示可以开始播放,3
表示媒体可以从头到尾播放 -
seekable
: 时间范围 可以搜索的时间范围 -
seeking
: 布尔值 表示播放器是否正移动到媒体文件中的新位置 -
start
:浮点数 取得或设置媒体文件中开始播放的位置,以秒表示 -
totalBytes
: 整数 当前资源所需的总字节数 -
videoHeight
: 整数 返回视频(不一定是元素)的高度。只适用于 -
videoWidth
: 整数 返回视频(不一定是元素)的宽度。只适用于 -
volume
:浮点数 取得或设置当前音量,值为0.0到1.0
事件有:
-
abort
下载中断 -
canplay
可以播放时;readyState
值为2 -
canplaythrough
: 播放可继续,而且应该不会中断;readyState
值为3 -
canshowcurrentframe
:当前帧已经下载完成;readyState
值为1 -
dataunavailable
:因为没有数据而不能播放;readyState
值为0 -
durationchange
:duration
属性的值改变 -
emptied
:网络连接关闭 -
empty
:发生错误阻止了媒体下载 -
ended
:媒体已播放到末尾,播放停止 -
error
:下载期间发生网络错误 -
load
: 所有媒体已加载完成。这个事件可能会被废弃,建议使用canplaythrough
-
loadeddata
:媒体的第一帧已加载完成 -
loadedmetadata
: 媒体的元数据已加载完成 -
loadstart
:下载已开始 -
pause
: 播放已暂停 -
play
: 媒体已接收到指令开始播放 -
playing
: 媒体已实际开始播放 -
progress
: 正在下载 -
ratechange
: 播放媒体的速度改变 -
seeked
:搜索结束 -
seeking
:正移动到新位置 -
stalled
浏览器尝试下载,但未接收到数据 -
timeupdate
:currentTime
被以不合理或意外的方式更新 -
volumechange
:volume
属性值或muted
属性值已改变 -
waiting
: 播放暂停,等待下载更多数据
//取得元素的引用
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";
}
});
//定时更新当前时间 以小于1000ms触发
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
//进一步处理
}
//可能是"probably"
if (audio.canPlayType("audio/ogg; codecs=\"vorbis\"")){ // MIME & 编码格式
//进一步处理
}
常用音频的音频格式和编解码器
-
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
类型
元素还有一个原生的
JavaScript
构造函数Audio
,可以在任何时候播放音频。从同为DOM
元素的角度看,Audio
与Image
很相似,但Audio
不用像Image
那样必须插入到文档中。只要创建一个新实例,并传入音频源文件即可。
var audio = new Audio("sound.mp3");
EventUtil.addHandler(audio, "canplaythrough", function(event){
audio.play();
})
// 创建实例即可开始下载指定的文件。下载完成后,调用play()就可以播放音频。
在iOS
中,调用play()
时会弹出一个对话框,得到用户的许可后才能播放声音。如果想在一段音频播放后再播放另一段音频,必须在onfinish
事件处理程序中调用play()
方法。
四、历史状态管理
history.pushState()
通过状态管理API
, 能够在不加载新页面的情况下改变浏览器的URL
。为此, 需要使用history.pushState()
方法,该方法可以接收三个参数:状态对象、新状态的标题和新URL
新URL
不必须为绝对路径。如果新URL
是相对路径,那么它将被作为相对于当前URL
处理。新URL
必须与当前URL
同源,否则 pushState()
会抛出一个异常。该参数是可选的,缺省为当前URL
。
// 假设在 http://mozilla.org/foo.html 中执行了以下 JS 代码:
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
// 第二个参数没有浏览器实现,可以传空字符串 或者一个短标题(安全的选择)。
// 这将使浏览器地址栏显示为 http://mozilla.org/bar.html
// 但并不会导致浏览器加载 bar.html ,甚至不会检查bar.html 是否存在。
执行pushState()
方法后,新的状态信息就会被加入历史状态栈,而浏览器地址栏也会变成新的相对URL
。状态改变之后查询location.href
也会返回与地址栏中相同的地址,但是浏览器并不会真的向服务器发送请求。
假设现在用户又访问了 http://google.com
,然后点击了返回按钮。此时,地址栏将显示 http://mozilla.org/bar.html
,同时页面会触发 popstate
事件,事件对象state
中包含了 stateObj
的一份拷贝。页面本身与 foo.html
一样,尽管其在 popstate
事件中可能会修改自身的内容。
如果我们再次点击返回按钮,页面URL
会变为http://mozilla.org/foo.html
,文档对象document
会触发另外一个 popstate
事件,这一次的事件对象state object
为null
。 这里也一样,返回并不改变文档的内容,尽管文档在接收 popstate
事件时可能会改变自己的内容,其内容仍与之前的展现一致。
EventUtil.addHandler(window, "popstate", function(event){
var state = event.state;
if (state){ //第一个页面加载时state 为空
// 进一步操作
}
})
history.replaceState()
history.replaceState()
与history.pushState()
非常相似,区别在于 replaceState()
是修改(替换)了当前的历史栈栈顶的状态信息,而不是新增。 注意这并不会阻止其在全局浏览器历史记录中创建一个新的历史记录项。
AURL
push到 BURL
,再push到CURL
,后退会后退到BURL
;
AURL
push到 BURL
,再replace到 CURL
,后退会后退到AURL
;
popstate
事件
每当活动的历史记录项发生变化时, popstate
事件都会被传递给window
对象。如果当前活动的历史记录项是被 pushState
创建的,或者是由 replaceState
改变的,那么 popstate
事件的状态属性 state
会包含一个当前历史记录状态对象的拷贝(调用这两个方法的第一个参数)
页面加载时,或许会有个非null
的状态对象。这是有可能发生的,举个例子,假如页面(通过pushState()
或replaceState()
方法)设置了状态对象而后用户重启了浏览器。那么当页面重新加载时,页面会接收一个onload
事件,但没有popstate
事件,但是此时访问history.state
属性会得到如同popstate
被触发时能得到的状态对象。