• iframe通过postMessage进行跨域通信以及在Angular中使用


    写在前面

    前端开发过程中,会遇到一些需要使用iframe的场景,使用iframe关键的一个点是数据之间的传输,基于同源的要求十分苛刻,大家基本上是都是跨域的,如果跨域进行数据传输呢?
    大家使用的比较多的就是postMessage()这个方法了,下面将具体展示如何在html中使用iframe进行数据传输,以及在angular框架中如何使用以及在angular中与html中的差异性

    普通html页面

    由外到内(向iframe内网页传输数据)

    使用iframe处
    <body>
        <iframe src="./iframe-content.html" class="iframe" frameborder="0"></iframe>
        <script>
          const iframeElement = document.querySelector(".iframe");
          //需要等待iframe加载完成后再发送信息,原因是 iframe的网页需要注册message事件,若先发消息再注册,那么在注册之前是收不到消息的
          iframeElement.addEventListener("load", () => {
            //相当于iframe自己给自己发消息
            iframeElement.contentWindow.postMessage("这是一条信息", "*");
          });
        </script>
      </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    iframe内容
    <body>
      <span>这里是iframe内容</span>
      <script>
        window.addEventListener("message", (event) => {
          console.log(event.data);
        });
      </script>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    由内到外

    使用iframe处
      <body>
        <iframe src="./iframe-content.html" class="iframe" frameborder="0"></iframe>
        <script>
          window.addEventListener("message", (event) => {
            console.log(event.data);
          });
        </script>
      </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    iframe内容
     <body>
        <span>这里是iframe内容</span>
        <script>
          //给上层级发消息,若上层级是顶层可以使用window.top
          window.parent.postMessage("给使用处发消息", "*");
        </script>
      </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在Angular使用

    • 首先是src 在angular中直接使用src链接会被认为是不安全的,需要通过DomSanitizer中的bypassSecurityTrustResourceUrl方法进行一个转化才可使用
    constructor(
        private sanitizer: DomSanitizer
    ) {
        this.src = this.sanitizer.bypassSecurityTrustResourceUrl(`${path}`);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 其次是在获取iframe 可以通过 @ViewChild来获取
    @ViewChild('iframe') iframeElement:ElementRef<HTMLIFrameElement>; 来进行获取
    
    • 1
    • 通过监听iframe load事件来判断接受事件是否注册不能使用了 ,就需要在iframe内部传来一条信息来通知事件是否注册完成
      iframeElement.addEventListener("load", () => {
            iframeElement.contentWindow.postMessage("这是一条信息", "*");
          });
    
    • 1
    • 2
    • 3
      window.parent.postMessage(true); //通知app事件注册成功
    
      	//接受iframe来的通知 基于rxjs去写事件的监听
       fromEvent<MessageEvent>(window, 'message').pipe(map(data => data.data))
        .pipe(takeUntil(this.ngUnsubscribe$))
        .subscribe(isLoaded => {
            if (isLoaded) {
                this.templatePreviewIframe.nativeElement.contentWindow.postMessage(数据);
            }
        });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    总结

    html

    <iframe
    #iframe
    [src]="src"
    frameborder="0"
    ></iframe>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    src:string;
    ngUnsubscribe$= new Subject();
    @ViewChild('iframe') iframeElement: ElementRef<HTMLIFrameElement>;
    constructor(
        private sanitizer: DomSanitizer
    ) {
        this.src = this.sanitizer.bypassSecurityTrustResourceUrl(`${path}`);
    }
    
    ngOnInit(){
        fromEvent<MessageEvent>(window, 'message').pipe(map(data => data.data))
            .pipe(takeUntil(this.ngUnsubscribe$))
            .subscribe(isLoaded => {
                if (isLoaded) {
                    this.templatePreviewIframe.nativeElement.contentWindow.postMessage(数据);
                }
            });
    }
    
    ngOnDestroy(){
        this.ngUnsubscribe$.next();
        this.ngUnsubscribe$.complete();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    iframe内容网页

    ngOnInit(){
        fromEvent(window, 'message').subscribe((event: MessageEvent<any>) => {
            //todo
        });
        window.parent.postMessage(true); //通知app事件注册成功
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    Asp.Net Core&Jaeger实现链路追踪
    生成神经网络是什么,生成神经网络的条件
    视频播放速度调节的chrome插件,怎么快捷键调节B站播放速度
    JVM垃圾回收总结
    idea中th:onclick报错问题最终解决办法
    .NET 程序读取当前目录避坑指南
    分分钟让你学会栈和队列
    nginx 基本使用、借助 nginx 和 mkcert 实现本地 https://localhost 测试。
    docker启动fastdfs
    设计模式再探——原型模式
  • 原文地址:https://blog.csdn.net/m0_54944506/article/details/132583412