zoukankan      html  css  js  c++  java
  • Angular2+ iframe跨域调用父页面js

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

    先来看看iframe跨域调用父页面的实现逻辑(以postMessage方式为例)

     (postMessage介绍:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage )

    1.父页面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组件通讯

    <!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;" 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>
  • 相关阅读:
    辛星和你彻底搞清CSS中的相对定位和绝对定位
    快速向表中插入大量数据Oracle中append与Nologging
    关于insert /*+ append*/ 各种insert插入速度比较
    dblink连接的目标端 session不断的问题。
    oracle操作记录
    ORACLE快速彻底Kill掉的会话
    Oracle 死锁的检测查询及处理
    Oracle 11g必须开启的服务及服务详细介绍
    oracle job有定时执行的功能,可以在指定的时间点或每天的某个时间点自行执行任务。
    Oracle报 ORA-00054资源正忙的解决办法
  • 原文地址:https://www.cnblogs.com/liaoshiqi/p/10558439.html
Copyright © 2011-2022 走看看