iframe的缺点
如果不考虑体验问题,iframe 几乎是最完美的微前端解决方案了。
iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
缺点:
- url不同步,浏览器刷新后页面丢失。
- UI不同步,dom结构不共享。比如弹窗居中问题。
- 全局上下文完全隔离,内存变量不共享。难以实现 iframe 内外系统的通信、数据同步等需求。
- 慢。每次子应用进入都是一次浏览器上下文重建,资源重新加载的过程。
<iframe src="xxxxx" id="xxxxx" name="xxxxx" ></iframe>
postMessage通信
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
:目标窗口(你想发送跨域消息的那个窗口),例如:iframe.contentWindowmessage
将要发送的数据targetOrigin
目标窗口的地址(URL),或者字符串*
表示无限制、任何URL都允许发送
1.消息发送-子页面发给父页面
window.parent.postMessage('xxxxx','http://a.index.com');
2.消息发送-父页面发给子页面
contentWindow 属性返回当前HTMLIFrameElement的Window对象. 你可以使用这个Window 对象去访问这个iframe的文档和它内部的DOM. 这个是可读属性, 但是它的属性像全局Window 一样是可以操作的.
const iFrame = document.getElementById('iframe')
<!-- 需要等到iframe中的子页面加载完成后才发送消息,否则子页面接收不到消息 -->
iFrame.onload = function(){
<!-- iFrame.contentWindow获取到iframe的window对象 -->
iFrame.contentWindow.postMessage('xxx','*');
}
3.消息接收-子父页面通用
if (typeof window.addEventListener != 'undefined') { // for ie9+、chrome
window.addEventListener('message', dealMessage, false);
} else if (typeof window.attachEvent != 'undefined') { // for ie8-
window.attachEvent('onmessage', dealMessage);
}
function dealMessage(e){
// 对消息来源origin做一下过滤,避免接收到非法域名的消息导致的xss攻击
if(e.origin==='http://a.index.com'){
console.log(e.origin) //发送端页面URL,这里是http://a.index.com
console.log(e.source) // 发送端window对象
console.log(e.data) // 发送的消息
}
}
4.示例
const param = '{"id":1}';
const message = '{"function":"func1","param":'+param+'}';
window.parent.postMessage(message,'*');
//是否存在指定函数
function isExitsFunction(funcName) {
try {
if (typeof(eval(funcName)) == "function") {
return true;
}
} catch(e) {}
return false;
}
//处理接收的消息
function dealMessage(e){
var obj = eval("("+e.data+")");
if(isExitsFunction(obj["function"])){
eval(obj["function"])(obj["param"]);
}
}
//处理业务逻辑
function func1(param){
//...........
}
引申:eval的用法 onload
window.parent 当前窗口的父窗口对象,如果没有返回自身
window.top 顶层窗口对象
window.frames 当前窗口的所有直接子窗口