iframe的缺点

Why Not Iframe

如果不考虑体验问题,iframe 几乎是最完美的微前端解决方案了。

iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。

缺点:

  1. url不同步,浏览器刷新后页面丢失。
  2. UI不同步,dom结构不共享。比如弹窗居中问题。
  3. 全局上下文完全隔离,内存变量不共享。难以实现 iframe 内外系统的通信、数据同步等需求。
  4. 慢。每次子应用进入都是一次浏览器上下文重建,资源重新加载的过程。
  1. <iframe src="xxxxx" id="xxxxx" name="xxxxx" ></iframe>

postMessage通信

otherWindow.postMessage(message, targetOrigin, [transfer]);

  • otherWindow:目标窗口(你想发送跨域消息的那个窗口),例如:iframe.contentWindow
  • message 将要发送的数据
  • targetOrigin 目标窗口的地址(URL),或者字符串*表示无限制、任何URL都允许发送

1.消息发送-子页面发给父页面

  1. window.parent.postMessage('xxxxx','http://a.index.com');

2.消息发送-父页面发给子页面

contentWindow 属性返回当前HTMLIFrameElementWindow对象. 你可以使用这个Window 对象去访问这个iframe的文档和它内部的DOM. 这个是可读属性, 但是它的属性像全局Window 一样是可以操作的.

  1. const iFrame = document.getElementById('iframe')
  2. <!-- 需要等到iframe中的子页面加载完成后才发送消息,否则子页面接收不到消息 -->
  3. iFrame.onload = function(){
  4. <!-- iFrame.contentWindow获取到iframewindow对象 -->
  5. iFrame.contentWindow.postMessage('xxx','*');
  6. }

3.消息接收-子父页面通用

  1. if (typeof window.addEventListener != 'undefined') { // for ie9+、chrome
  2. window.addEventListener('message', dealMessage, false);
  3. } else if (typeof window.attachEvent != 'undefined') { // for ie8-
  4. window.attachEvent('onmessage', dealMessage);
  5. }
  6. function dealMessage(e){
  7. // 对消息来源origin做一下过滤,避免接收到非法域名的消息导致的xss攻击
  8. if(e.origin==='http://a.index.com'){
  9. console.log(e.origin) //发送端页面URL,这里是http://a.index.com
  10. console.log(e.source) // 发送端window对象
  11. console.log(e.data) // 发送的消息
  12. }
  13. }

4.示例

  1. const param = '{"id":1}';
  2. const message = '{"function":"func1","param":'+param+'}';
  3. window.parent.postMessage(message,'*');
  1. //是否存在指定函数
  2. function isExitsFunction(funcName) {
  3. try {
  4. if (typeof(eval(funcName)) == "function") {
  5. return true;
  6. }
  7. } catch(e) {}
  8. return false;
  9. }
  10. //处理接收的消息
  11. function dealMessage(e){
  12. var obj = eval("("+e.data+")");
  13. if(isExitsFunction(obj["function"])){
  14. eval(obj["function"])(obj["param"]);
  15. }
  16. }
  17. //处理业务逻辑
  18. function func1param){
  19. //...........
  20. }

引申:eval的用法 onload

  1. window.parent 当前窗口的父窗口对象,如果没有返回自身
  2. window.top 顶层窗口对象
  3. window.frames 当前窗口的所有直接子窗口

参考iframe跨域通信(postMessage)