React Iframe 使用探索

摘要:
接下来的两行通过contentWindow.document.body.offsetHeight获取iframe页面高度,这便于后续的自适应调整+60由于样式中会生成其他高度,因此此处将其用作缓冲区,可根据实际使用中的需要进行调整。加载页面后执行componentDidMount函数。React的典型语法是添加父级事件侦听iframe。window.addEventListener;无法修改第一个参数。事件名称是message,第二个参数是eventHandler。这里,使用外部定义的receiveMessageFromIframe方法。第三个参数是默认值。receiveMessageFromIframe函数是事件侦听的处理函数。注意,React还将使用消息数据来驱动。因此,这里有一个以setImmediate开头的消息过滤器,用于捕获iframe真正传输的数据。

作者后端经验比较丰富,近期要做跨域跨前端框架的前端页面展示,自然联想到了 IFRAME 方法,细致了解下来发现它可以用来解决很多棘手问题,包括:

  • 跨域问题
  • Ajax 前进后退问题
  • 异步上传问题
  • 跨框架问题
父页面

基础 React 框架

import React, { PureComponent } from 'react';

export default class Iframe extends PureComponent {

    render () {
        return (
            <div>
                <h1>Parent</h1>
                <p>Send Message 
                    <button id="message_button" onClick={this.handleParentClick.bind(this)}>Hi child</button>
                </p>
                <span> Show Message </span>
                <div id='results'></div>
            </div>
        );
    }
}

importexport 外部都是 React 基本框架,内部显示了页面布局:

 
React Iframe 使用探索第1张
Parent

Parent 提示当前部分是父页面;
Send MessageHi child 按钮用来向 iframe 传递消息,按钮绑定了点击事件 handleParentClick,后文会定义;
Show Messageresults div 用来展示 iframe 传来的消息,后文会做处理。

iframe 相关事件

export default class Iframe extends PureComponent {

    receiveMessageFromIframe ( event ) {
        // React will send message started with setImmediate
        if (!event.data.startsWith('setImmediate')){  
          console.log("parent received", event.data);
          const results = document.getElementById('results');
          results.innerHTML = event.data;
        }
    }

    componentDidMount () {
         // "message" name cannot be changed
        window.addEventListener("message", this.receiveMessageFromIframe, false); 
    }

    handleParentClick = () => {
        //必须是iframe加载完成后才可以向子域发送数据
        const childFrameObj = document.getElementById('myFrame');
        childFrameObj.contentWindow.postMessage("This is parent", '*');
        console.log("iframe height", childFrameObj.contentWindow.document.body.offsetHeight);
        childFrameObj.height = childFrameObj.contentWindow.document.body.offsetHeight + 60;  // there will be some margin and stylistic height
        console.log("iframe window", childFrameObj.contentWindow);
        console.log("iframde document", childFrameObj.contentWindow.document);
        console.log("iframe html", childFrameObj.contentWindow.document.documentElement);
    }
    
    render () {
        ...
    }
}
  • handleParentClick 函数是处理 Hi child 按钮点击事件的:

    1. 先从 DOM 中获得名字为 myFrame 的节点(后文 iframe 部分会展示)。
    2. 通过 contentWindow.postMessage 方法向 iframe 传递信息,参数有两个,第一个是传递的信息内容(This is parent),另一个是 targetOrigin,即目标域,* 表示当前域,也可以写成 http://baidu.com 等其他域名,但注意 iframe 的域必须和这个域名一致。
    3. 后面 2 行通过 contentWindow.document.body.offsetHeight 获得 iframe 页面高度,方便后续做自适应调整,+60 因为样式上会产生其他的高度,这里是作为 buffer,实际使用中根据需要调整。
    4. 后面 3 行通过打印的方式展现常用可以获取的 iframe 信息,包括 window, document, html 等。
  • componentDidMount 函数是在页面加载后执行,React 的典型语法,这里增加了 parent 对 iframe 的事件监听。

    window.addEventListener("message", this.receiveMessageFromIframe, false); 
    

    第一个参数不能修改,事件名称是 message,第二个参数是 eventHandler,这里使用外面定义的 receiveMessageFromIframe 方法,第三个参数是默认值。

  • receiveMessageFromIframe 函数是事件监听的处理函数,注意 React 也会使用 message 数据驱动,所以这里有过滤 message 以 setImmediate 开头的信息,以捕获 iframe 真正传输的数据。获得数据后在展示区 results div 添加获得的信息。
iframe 页面
export default class Iframe extends PureComponent {
    render () {
        return (
             <div>
                ...
                <iframe
                  id="myFrame"
                  width="100%"
                  height={0}
                  frameBorder={1}
                  scrolling="no"
                  srcDoc="
                  <h1>myFrame</h1>
                  <p>Send Message: <button id='message_button'}>Hi parent</button></p>
                  <span>Show Message</span>
                  <div id='results'></div>
                  <script>
                      function receiveMessageFromParent ( event ) {
                        let results = document.getElementById('results');
                        results.innerHTML += event.data + '<br>';
                      };
                      window.addEventListener('message', receiveMessageFromParent, false);
        
                      let messageButton = document.getElementById('message_button');
                      /* console.log('msg button', messageButton); annoataion cannot use //  */
                      messageButton.addEventListener('click', function (e) {
                        console.log('iframe send msg');
                        console.log('parent', window.parent);
                        console.log('top container', window.top);
                        window.parent.postMessage('This is child', '*');
                      }, false);
                  </script>
                  "
                />
             </div>
        );
    }
}

原生 html 页面

id 是 DOM 上节点名称,上文有使用这里的 myFrame 来获得节点进行操作;
width="100%" 是 iframe 宽度,可以是百分比或者数值,百分比可以自适应页面;
frameBorder={1} 是 iframe 边框是否展示,1 代表展示,0 代表不展示;
scrolling="no" 是滚动设置,yes 代表展示,no 代表不展示,auto 代表自动识别;
height={0} 是 iframe 高度,可以是百分比或者数值,这里设置为 0 代表无内容不展示,有内容后上文根据内容高度自适应展示;
srcDoc=<string> 是 iframe 的 DOM,可以使用原生 HTML 编写;
src 是 iframe 的信息源。
srcDoc 内设置了 iframe 页面:

  1. myFrame 提示当前是 iframe 页面;
  2. Send MessageHi parent 是信息传输部分;
  3. Show Messageresults 用来展示从 parent 接受到的信息。

js 控制脚本

  • receiveMessageFromParent 函数用来控制从 parent 接受到信息后展示在展示区;
  • window.addEventListener 用来初始化事件监听,和 parent 的事件监听机制一样,不赘述;
  • messageButton 获取了当前组件的点击按钮;
  • messageButton.addEventListener 在点击按钮上绑定了点击事件,注意点击事件名称不可修改,是 click,向 parent 传递消息使用 window.parent.postMessage,和 parent 的 postMessage 参数一致,不赘述。
  • 注意:iframe 使用的原生 html 页面注释不能使用 // 方法,只能使用 /* */ 完成。
整体代码和效果
import React, { PureComponent } from 'react';

export default class Iframe extends PureComponent {

  receiveMessageFromIframe ( event ) {
    if (!event.data.startsWith('setImmediate')){  // React will send message started with setImmediate
      console.log("parent received", event.data);
      const results = document.getElementById('results');
      results.innerHTML = event.data;
    }
  }

  componentDidMount () {
    window.addEventListener("message", this.receiveMessageFromIframe, false);  // "message" name cannot be changed
  }

  handleParentClick = () => {
    //必须是iframe加载完成后才可以向子域发送数据
    const childFrameObj = document.getElementById('myFrame');
    childFrameObj.contentWindow.postMessage("This is parent", '*');
    console.log("iframe height", childFrameObj.contentWindow.document.body.offsetHeight);
    childFrameObj.height = childFrameObj.contentWindow.document.body.offsetHeight + 60;  // there will be some margin and stylistic height
    console.log("iframe window", childFrameObj.contentWindow);
    console.log("iframde document", childFrameObj.contentWindow.document);
    console.log("iframe html", childFrameObj.contentWindow.document.documentElement);
  }

  render () {
    

    return (
      <div>
        <h1>Parent</h1>
        <p>Send Message <button id="message_button" onClick={this.handleParentClick.bind(this)}>Hi child</button></p>
        <span>Show Message </span>
        <div id='results'></div>
        <iframe
          id="myFrame"
          width="100%"
          height={0}
          frameBorder={1}
          scrolling="no"
          srcDoc="
          <h1>myFrame</h1>
          <p>Send Message: <button id='message_button'}>Hi parent</button></p>
          <span>Show Message</span>
          <div id='results'></div>
          <script>
              function receiveMessageFromParent 

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇HTML5扩展之微数据与丰富网页摘要itemscope, itemtype, itemprop转:Android设置全局变量下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

在html页面中引入另一个html页面

我们在使用html编写一个网站的时候,通常情况下头部和尾部是相同的,如果一个网站的每个页面都把这些代码写一遍,不仅浪费时间,还显得重复代码很多,所以此时把重复的页面单独摘出来,在用到的时候从外部直接引进去,就能节省很多时间,减少很多代码。 在这里,有好几种引入html文件的方式,不过每种都是有利有弊,需要根据需要自行选择 如果有些浏览器本地实现不了,那么放...

python selenium 基本常用操作

 最近学习UI自动化,把一些常用的方法总结一下,方便自己以后查阅需要。因本人水平有限,有不对之处多多包涵!欢迎指正! 一、xpath模糊匹配定位元素 武林至尊,宝刀屠龙刀(xpath),倚天不出(css),谁与争锋  学会了xpath,妈妈再也不用担心我定位不到元素啦 ^_^ # coding:utf-8 import time from seleniu...

Javascript跨域问题解决方案

---本方法来自网上,因最近项目需求,解决了三天未果,最终发现此文并测试可用。 一个 非常优雅绝妙的解决方案!话不多说,直接上解决方案原理图: 该图要解决的问题说明如下:在AAA.com域名下的index.htm页面中内嵌了BBB.com域名下的一个页面index.htm,正常情况下iframe内部的index.htm页面是无法访问父页面index.ht...

未分类[selenium]-元素定位不到的原因及解决办法

摘自-宋现锋《测试开发工程师丛书》,如有版权问题请及时联系本人,谢谢. 在我们编写自动化测试用例的过程中,经常会遇到元素定位不到的现象,有的时候我们用 Selenium IDE 检查的时候也能在 Firebug 中看到,可是运行代码的时候,总是提示元素找不到。经过我以往和经验和大家在网上的讨论,我总结了以下几种情况: (1) 定位属性值是动态变化的情况 现...

基于HTML5的iPad电子杂志横竖屏自适应方案

基于HTML5的iPad电子杂志横竖屏自适应方案 (转载自:http://www.yeeach.com/?p=1172) 基于HTML5来制作iPad电子杂志,横屏及竖屏自适应是个大问题,查找了半天资料,没有一篇像样的文章可供参考。将思路及例子分享一下。例子并不严谨和规范,仅供参考。 大致思路: 1、对横屏(portrait)和竖屏(landscape)情...

防止 XSS 攻击 解决方案

1、 XSS又叫CSS英文缩写为Cross Site Script中文意思为跨站脚本攻击具体内容指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的. 解决方案 第一。过滤 过滤 标签 等字符 ,但是这样 对用户是不公平的。 第二。用asii 码替换 如 <  &...