业务场景:列表页面添加一个导入功能,该导入功能由第三方页面提供,导入完成后需要通知主列表刷新数据。
先来看看iframe跨域调用父页面的实现逻辑(以postMessage方式为例)
(postMessage介绍:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage )
1.父页面html
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script type="text/javascript"> window.onload = function () { //添加监听事件。 if (typeof window.addEventListener != "undefined") window.addEventListener("message", func, false); else if (typeof window.attachEvent != 'undefined')//兼容不支持addEventLinstener的IE。 window.attachEvent("onmessage", func); } //被调用的函数。 function invocationTarget(msg) { if (msg) alert(msg); else alert("~~~"); } //监听事件回调函数。 function func(e) { if (e.data.Result) invocationTarget(e.data.Data); } </script> </head> <body> <iframe src="子页面域名/HtmlPage.html" style="border:0px"></iframe> </body> </html>2. 子页面html
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script type="text/javascript"> function invocation() { var data = { Result: true, Data: 'hello world' }; //第一个参数表示要传递的参数,第二个参数表示要传递到的目标。 window.parent.postMessage(data, "父页面域名/HtmlPage.html"); } </script> </head> <body> <input onclick="invocation();" type="button" /> </body> </html>以上逻辑是基于父页面是html实现的,见红色字体标注,子页面回调给指定的窗口源。
来看看postMessage参数说明:
postMessage(data,origin)方法接受两个参数
1.data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。
2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
到此就出现另一个问题了:angular弹窗式组件如何通过URL反映?也就是如何把父页面集成到组件中。
因为组件和js通讯是很好实现的,这样我们可以设法把父页面嵌套在组件中(iframe方式嵌套)
UrlIframeModalComponent组件通过Iframe嵌套IframeModal.html父页面,IframeModal.html父页面通过Iframe嵌套第三方子页面 testurl/
1.UrlIframeModalComponent.html 组件(模态弹出)
<iframe width="100%" height="100%" style="overflow:auto;" frameborder="0" \[src\]=" _/assets/IframeModal.html_ | safe"> </iframe>UrlIframeModalComponent.ts
export class UrlIframeModalComponent implements OnInit {
constructor() { }
ngOnInit() {
//添加监听事件:监听由 IframeModal.html发出的callBackFromIframe事件
document.addEventListener('callBackFromIframe', this.callBack);
}
callBack(evt){
//回调参数
const param = evt.param;
console.log(param);
}
ngOnDestroy() {
document.removeEventListener("callBackFromIframe", this.callBack); //销毁监听,否则会多次接收
}
}
2._IframeModal.html 父页面,与第三方子页面及UrlIframeModalComponent组件通讯**_
**
3.第三方子页面
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="css/default.css" type="text/css" rel="stylesheet">
</head> <body><div id="mainDiv">
<div id="content">
这是第三方页面功能...
(导入文件功能)
<br />
<br />
<a style="color:blue; cursor: pointer;" onclick="notifyBack('导入完成')">导入完成</a>
<a style="color:blue; cursor: pointer;" onclick="notifyBack('取消')">取消</a>
</div>
</div>
<script type="text/javascript">
function notifyBack(msg) {
var data = {
Result: true,
Data: msg
};
//第一个参数表示要传递的参数,第二个参数表示要传递到的目标。
window.parent.postMessage(data, "http://localhost:4200/assets/IframeModal.html");
}
</script>
</body> </html>