Cross-document messaging
平时做web开发的时候关于消息传递,除了客户端与服务器传值,还有几个经常会遇到的问题
1..多窗口之间消息传递
2.主页面与嵌套的iframe消息传递
上面问题的跨域数据传递如何进行?
由于同源策略的限制,JavaScript 跨域的问题,一直是一个颇为棘手的问题。
HTML5 提供了在网页文档之间互相接收与发送信息的功能。使用这个功能,只要获取到网页所在窗口对象的实例,不仅同源(域 + 端口号)的 Web 网页之间可以互相通信,甚至可以实现跨域通信。
要想接收从其他窗口发送来的信息,必须对窗口对象的 onmessage 事件进行监听,其它窗口可以通过 postMessage 方法来传递数据。
postMessage 的作用就是传递数据,而 onmessage 的作用就是接收数据
发送消息
windowObj.postMessage(data,origin)方法说明:
1、windowObj: 窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。(接收方窗口的引用)
2、data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化。
3、origin:字符串参数,指明目标窗口的源,协议+主机+端口号,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以将参数设置为"*",这样可以传递给任意窗口(好像不是这样),如果要指定和当前窗口同源的话设置为"/"。
接收消息
注册事件监听
element.addEventListener(event, function, useCapture);
第一个参数是事件的类型 (如 "click" 或 "mousedown"等等).
第二个参数是事件触发后调用的函数。
第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。
注意:event不要使用 "on" 前缀。 例如,使用 "click" ,而不是使用 "onclick"。
事件冒泡或事件捕获?
事件传递有两种方式:冒泡与捕获。
事件传递定义了元素事件触发的顺序。 如果你将 <p> 元素插入到 <div> 元素中,用户点击 <p> 元素, 哪个元素的 "click" 事件先被触发呢?
在 冒泡 中,内部元素的事件会先被触发,然后再触发外部元素,即: <p> 元素的点击事件先触发,然后会触发 <div> 元素的点击事件。
在 捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件,即: <div> 元素的点击事件先触发 ,然后再触发 <p> 元素的点击事件。
addEventListener() 方法可以指定 "useCapture" 参数来设置传递类型:
addEventListener(event, function, useCapture);
默认值为 false, 即冒泡传递,当值为 true 时, 事件使用捕获传递。
关于message事件
onmessage 该事件通过或者从对象(WebSocket, Web Worker, Event Source 或者子 frame 或父窗口)接收到消息时触发。
测试示例(跨域:父窗口 127.0.0.1 ,子窗口 localhost):
http://127.0.0.1:8080/test01/parent.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Test Cross-domain communication using HTML5</title> <script type="text/JavaScript"> function sendMsg(){ // 通过 postMessage 向子窗口发送数据 document.getElementById("otherPage").contentWindow .postMessage( document.getElementById("message").value, //"http://localhost:8080" "*" ); } window.addEventListener("message", function( event ) { alert(event.data); }, false ); </script> </head> <body> <!-- 通过 iframe 嵌入子页面 --> <iframe src="http://localhost:8080/test01/child.html" id="otherPage" > </iframe> <br/><br/> <input type="text" id="message"> <input type="button" value="Send to localhost" onclick="sendMsg()" /> </body> </html>
http://localhost:8080/test01/child.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Web page from child.com</title> <script type="text/JavaScript"> //event 参数中有 data 属性,就是父窗口发送过来的数据 window.addEventListener("message", function( event ) { //检查事件来源 if(event.origin !== 'http://127.0.0.1:8080'){ return; } // 把父窗口发送过来的数据显示在子窗口中 document.getElementById("content").innerHTML+=event.data+"<br/>"; //回复消息 event.source.postMessage('ok!', //event.origin "*" ); }, false ); </script> </head> <body> Web page from http://localhost:8080 <div id="content"></div> </body> </html>
通过浏览器访问:http://127.0.0.1:8080/test01/parent.html
输入 hello,点击发送按钮。
MessageEvent属性
不解的地方:
windowObj.postMessage(data,origin),既然windowObj是接收方窗口的引用,那么接收方就固定了,指定origin又有什么意义呢?