您的位置:首页 > Web前端 > HTML5

HTML5 脚本编程之:跨文档消息传递&历史状态管理

2017-03-14 13:35 459 查看

跨文档消息传递

跨文档消息传送(cross-document messaging),有时候简称为 XDM,指的是在来自不同域的页面间传递消息。

什么是同一个域:

例如如下地址中,http://www.a.example.com/dir/page.html

协议是http://,域名是www.a.example.com(其中example为一级域名,a为二级域名…),端口是80(默认端口可以省略)。

XDM只解决来自不同域的页面之间传递消息的问题,而不同协议的跨源访问则不在我们的讨论范围之内。

在 XDM 机制出现之前,要稳妥地实现跨域通信需要花很多工夫。XDM 把这种机制规范化,让我们能既稳妥又简单地实现跨文档通信。

核心方法 postMessage()

这个方法的目的是为了向目标文档传递数据。在 HTML5 规范中,除了 XDM 部分之外的其他部分也会提到这个方法名。

但是对于 XDM 而言,目标文档则指的是包含在当前页面中的< iframe >元素,或者由当前页面弹出的窗口。

postMessage()方法接收两个参数:

1、一条消息

2、字符串,指明消息接收方的文档必须来自某个特定域。

第二个参数对保障安全通信非常重要,可以防止浏览器把消息发送到不安全的地方。

来看下面的例子。

//注意:所有支持 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 处理程序的事件对象(event)包含以下三方面的重要信息。

data:作为 postMessage()第一个参数传入的字符串数据。
origin:发送消息的文档所在的域,例如"http://www.wrox.com"。
source:发送消息的文档的 window 对象的代理。这个代理对象主要用于在发送上一条消息的窗口中调用 postMessage()方法。如果发送消息的窗口来自同一个域,那这个对象就是 window。


事件监听

处于安全方面的考虑,接收到消息后验证发送窗口的来源是至关重要的。就像给 postMessage()方法指定第二个参数, 以确保浏览器不会把消息发送给未知页面一样,在 onmessage 处理程序中应该检测消息来源,这样可以确保传入的消息来自已知的页面。

基本的检测模式如下:

EventUtil.addHandler(window, "message", function(event){
//确保发送消息的域是已知的域
if (event.origin == "http://www.wrox.com"){
//处理接收到的数据 processMessage(event.data);
//可选:向来源窗口发送回执
event.source.postMessage("Received!", "http://p2p.wrox.com");
}
});


注意:event.source 大多数情况下只是 window 对象的代理,并非实际的 window 对象。换句话说,不能通过这个代理对象访问 window 对象的其他任何信息。但是可以通过这个代理调用 postMessage(),这个方法永远存在,永远可以调用。

另外还有一些需要注意的是:

首先,postMessage()的第一个参数最早是作为“永远都是字符串”来实现的。但后来这个参数的定义改了,改成允许传入任何数据结构。可是,并非所有浏览器都实现了这一变化。为保险起见,使用 postMessage()时,最好还是只传字符串。如果你想传入结构化的数据,最佳选择是先在要传入的数据上调用 JSON.stringify(),通过 postMessage()传入得到的字符串,然后再在 onmessage 事件处理程序中调用 JSON.parse()。

支持 XDM 的浏览器有 IE8+、Firefox 3.5+、Safari 4+、Opera、Chrome、iOS 版 Safari 及 Android 版 WebKit。XDM 已经作为一个规范独立出来,现在它的名字叫 Web Messaging,官方页面是 http://dev.w3.org/html5/postmsg/

历史状态管理

在现代 Web 应用中,用户的每次操作不一定会打开一个全新的页面(例如Ajax),因此“后退”和“前进”按钮也就失去了作用,导致用户很难在不同状态间切换。 要解决这个问题,首选使用 hashchange 事件。再者,HTML5 通过更新 history 对象为管理历史状态提供了方便。

hashchange

HTML5 新增了 hashchange 事件,以便在 URL 的参数列表( URL 中“#”号后面的所有字符串) 发生变化时通知开发人员。之所以新增这个事件,是因为在 Ajax 应用中,开发人员经常要利用 URL 参数列表来保存状态或导航信息。

必须要把 hashchange 事件处理程序添加给 window 对象,然后 URL 参数列表只要变化就会调用 它。此时的 event 对象应该额外包含两个属性:oldURL 和 newURL。这两个属性分别保存着参数列表 变化前后的完整 URL。

EventUtil.addHandler(window, "hashchange", function(event){
alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
});


支持 hashchange 事件的浏览器有 IE8+、Firefox 3.6+、Safari 5+、Chrome 和 Opera 10.6+。在这些浏览器中,只有 Firefox 6+、Chrome 和 Opera 支持 oldURL 和 newURL 属性。为此,最好是使用 location(location.hash)对象来确定当前的参数列表。

使用以下代码可以检测浏览器是否支持 hashchange 事件:

var isSupported = ("onhashchange" in window); //这里有 bug


如果 IE8 是在 IE7 文档模式下运行,即使功能无效它也会返回 true。为解决这个问题,可以使用以下这个更稳妥的检测方式。

var isSupported = ("onhashchange" in window) && (document.documentMode === undefined || document.documentMode > 7);


history

HTML5 通过更新 history 对象为管理历史状态提供了方便。

通过 hashchange 事件,可以知道 URL 的参数什么时候发生了变化,即什么时候该有所反应。而通过状态管理 API,能够在不加载新页面的情况下改变浏览器的 URL。

为此,需要使用
history.pushState()
方法,该方法可以接收三个参数:状态对象、新状态的标题和可选的相对 URL。

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


执行 pushState()方法后,新的状态信息就会被加入历史状态栈,而浏览器地址栏也会变成新的 相对 URL。

但是,浏览器并不会真的向服务器发送请求,即使状态改变之后查询 location.href 也会返回与地址栏中相同的地址。另外,第二个参数目前还没有浏览器实现,因此完全可以只传入一个空字 符串,或者一个短标题也可以。而第一个参数则应该尽可能提供初始化页面状态所需的各种信息。

因为 pushState()会创建新的历史状态,所以你会发现“后退”按钮也能使用了。按下“后退” 按钮,会触发 window 对象的 popstate 事件。popstate 事件的事件对象有一个 state 属性,这个属性就包含着当初以第一个参数传递给 pushState()的状态对象。

EventUtil.addHandler(window, "popstate", function(event){
var state = event.state;
if (state){
//第一个页面加载时 state 为空
processState(state);
}
});


得到这个状态对象后,必须把页面重置为状态对象中的数据表示的状态(因为浏览器不会自动为你做这些)。记住,浏览器加载的第一个页面没有状态,因此单击“后退”按钮返回浏览器加载的第一个页面时,event.state 值为 null。

要更新当前状态,可以调用 replaceState(),传入的参数与 pushState()的前两个参数相同。 调用这个方法不会在历史状态栈中创建新状态,只会重写当前状态。

支持 HTML5 历史状态管理的浏览器有 Firefox 4+、Safari 5+、Opera 11.5+和 Chrome。在 Safari 和 Chrome 中,传递给 pushState()或 replaceState()的状态对象中不能包含 DOM 元素。而 Firefox 支持在状态对象中包含 DOM 元素。Opera 还支持一个 history.state 属性,它返回当前状态的状态对象。

注意:在使用 HTML5 的状态管理机制时,请确保使用 pushState()创造的每一个“假” URL,在 Web 服务器上都有一个真的、实际存在的 URL 与之对应。否则,单击“刷新”按钮会导致 404 错误。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  html5