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事件注册成功
}
相关推荐
wenzhangli71 小时前
Ooder A2UI 核心架构深度解析:WEB 拦截层的设计与实现
前端·架构
前端百草阁2 小时前
【前端性能优化全链路指南】从开发编写到构建运行的多维度实践
前端·性能优化
神探小白牙2 小时前
eCharts 多系列柱状图增加背景图
javascript·ecmascript·echarts
女生也可以敲代码2 小时前
AI时代下的50道前端开发面试题:从基础到大模型应用
前端·面试
ZhengEnCi2 小时前
M5-markconv自定义CSS样式指南 📝
前端·css·python
IT_陈寒3 小时前
SpringBoot自动配置的坑差点让我加班到天亮
前端·人工智能·后端
xingpanvip3 小时前
星盘接口开发文档:星相日历接口指南
android·开发语言·前端·css·php·lua
@PHARAOH3 小时前
WHAT - GitLens supercharged 插件
前端
TT模板3 小时前
苹果cms整合西瓜播放器XGplayer插件支持跳过片头尾
前端·html5
Wect4 小时前
React 性能优化精讲
前端·react.js·性能优化