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

写在前面

在前端开发过程中,会遇到一些需要使用iframe的场景,使用iframe关键的一个点是数据之间的传输,基于同源的要求十分苛刻,大家基本上是都是跨域的,如果跨域进行数据传输呢?

大家使用的比较多的就是postMessage()这个方法了,下面将具体展示如何在html中使用iframe进行数据传输,以及在angular框架中如何使用以及在angular中与html中的差异性

普通html页面

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

使用iframe处

javascript 复制代码
<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>

iframe内容

javascript 复制代码
<body>
  <span>这里是iframe内容</span>
  <script>
    window.addEventListener("message", (event) => {
      console.log(event.data);
    });
  </script>
</body>

由内到外

使用iframe处

javascript 复制代码
  <body>
    <iframe src="./iframe-content.html" class="iframe" frameborder="0"></iframe>
    <script>
      window.addEventListener("message", (event) => {
        console.log(event.data);
      });
    </script>
  </body>

iframe内容

javascript 复制代码
 <body>
    <span>这里是iframe内容</span>
    <script>
      //给上层级发消息,若上层级是顶层可以使用window.top
      window.parent.postMessage("给使用处发消息", "*");
    </script>
  </body>

在Angular使用

  • 首先是src 在angular中直接使用src链接会被认为是不安全的,需要通过DomSanitizer中的bypassSecurityTrustResourceUrl方法进行一个转化才可使用
javascript 复制代码
constructor(
    private sanitizer: DomSanitizer
) {
    this.src = this.sanitizer.bypassSecurityTrustResourceUrl(`${path}`);
}
  • 其次是在获取iframe 可以通过 @ViewChild来获取
javascript 复制代码
@ViewChild('iframe') iframeElement:ElementRef<HTMLIFrameElement>; 来进行获取
  • 通过监听iframe load事件来判断接受事件是否注册不能使用了 ,就需要在iframe内部传来一条信息来通知事件是否注册完成
javascript 复制代码
  iframeElement.addEventListener("load", () => {
        iframeElement.contentWindow.postMessage("这是一条信息", "*");
      });
javascript 复制代码
  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(数据);
        }
    });

总结

html

go 复制代码
<iframe
#iframe
[src]="src"
frameborder="0"
></iframe>
go 复制代码
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();
}

iframe内容网页

go 复制代码
ngOnInit(){
    fromEvent(window, 'message').subscribe((event: MessageEvent<any>) => {
        //todo
    });
    window.parent.postMessage(true); //通知app事件注册成功
}
相关推荐
计算机软件程序设计1 分钟前
Vue中有什么组件可以实现轮播效果,每次出现四个元素?
前端·javascript·vue.js
GISer_Jing1 小时前
[本周五题]Javascript面试常考题&手撕&场景UR缓存、new关键字、大数相加、最长递增子序列、高并发请求、大文件上传和WebWorks
开发语言·javascript·面试
好_快1 小时前
Lodash源码阅读-baseIndexOf
前端·javascript·源码阅读
古柳_Deserts_X1 小时前
这个强大的插件能让网页里的 Shader 代码一览无余
前端·webgl·three.js
好_快1 小时前
Lodash源码阅读-indexOf
前端·javascript·源码阅读
积水成江1 小时前
【Vue3+Vite指南】全局引入SCSS文件后出现Undefined mixin?一招解决命名空间陷阱!
前端·vue.js·html5·scss
一个处女座的程序猿O(∩_∩)O1 小时前
harmonyOS NEXT开发与前端开发深度对比分析
前端·华为·harmonyos
泫凝1 小时前
NPM 常用操作指令大全
前端·npm·node.js
小妖6661 小时前
nexus搭建npm私服
前端·npm·node.js·nexus