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事件注册成功
}
相关推荐
WeiXiao_Hyy22 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡39 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone1 小时前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king2 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳2 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵3 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星3 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js