业务场景:列表页面添加一个导入功能,该导入功能由第三方页面提供,导入完成后需要通知主列表刷新数据。

先来看看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 οnclick="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组件通讯



<!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(param) { 
    
 
    

          //接收到子页面消息后,通知组件 
    
 
    

          var evt = document.createEvent("HTMLEvents"); 
    
 
    

          evt.param = param; 
    
 
    

          evt.initEvent("callBackFromIframe", false, false); 
    
 
    

          parent.window.document.dispatchEvent(evt); 
    
 
    

        } 
    
 
    

        //监听事件回调函数。 
    
 
    

        function func(e) { 
    
 
    

          if (e.data.Result == true) 
    
 
    

            invocationTarget(e.data); 
    
 
    

      } 
    
 
    

      </script> 
    
 
    

      </head> 
    
 
    

      <body> 
    
 
    

      <iframe src="http://.../第三方子页面.html" style="border:0px"></iframe> 
    
 
    

      </body> 
    
 
    

      </html>


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;" οnclick="notifyBack('导入完成')">导入完成</a> 
    
 
    

                  <a style="color:blue; cursor: pointer;" οnclick="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>