如何设置React组件的iframe内容 [英] How to set iframe content of a react component

查看:102
本文介绍了如何设置React组件的iframe内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在React组件中设置iframe的内容,但是我无法做到这一点.我有一个组件,其中包含一个在iframe完成加载后必须调用的函数.在该函数中,我正在设置内容,但似乎根本没有调用onload函数.我正在Chrome浏览器中对其进行测试.我正在尝试以下操作:

I am trying to set the content of an iframe in a React component but I am not able to do it. I have a component in which contains a function which has to be called when the iframe finishes loading. In that function i am setting the content but it doesnt seem like the onload function is called at all. I am testing it in chrome browser. I am trying the following:

var MyIframe = React.createClass({
    componentDidMount : function(){
        var iframe = this.refs.iframe.getDOMNode();
        if(iframe.attachEvent){
            iframe.attacheEvent("onload", this.props.onLoad);
        }else{
            iframe.onload = this.props.onLoad;
        }
    },
    render: function(){
        return <iframe ref="iframe" {...this.props}/>;
    }
});

var Display = React.createClass({
    getInitialState : function(){
        return {
            oasData : ""
        };
    },
    iframeOnLoad : function(){
        var iframe = this.refs.bannerIframe;
        iframe.contentDocument.open();
        iframe.contentDocument.write(['<head></head><style>body {margin: 0; overflow: hidden;display:inline-block;} html{ margin: 0 auto; text-align: center;} body > a > img {max-width: 100%; height: inherit;}', extraCss, '</style></head><body>', this.state.oasData.Ad[0].Text, '</body>'].join(''));
        iframe.contentDocument.close();
    },
    setOasData : function(data){
        this.setState({
            oasData : JSON.parse(data)
        });
    },
    componentDidMount : function(){
        var url = "getJsonDataUrl";

        var xhttp = new XMLHttpRequest();
        var changeOasDataFunction = this.setOasData;
        xhttp.onreadystatechange = function () {
            if (xhttp.readyState == 4 && xhttp.status == 200) {
                changeOasDataFunction(xhttp.responseText);
            }
        };
        xhttp.open("GET", url, true);
        xhttp.send();
    },
    render : function(){
        return (
            <MyIframe refs="bannerIframe" onLoad={this.iframeOnLoad} />
        );
    }
});

module.exports = Display;

我在做什么错了?

推荐答案

TLDR; https://codesandbox.io/s/react-iframe-examples-36k1x

如果您正在寻找一种通过事实上的规范方式通过React控制<iframe>内容的方法,请门户是您的理想之选. 与所有事物一样,Portal:一旦您建立了对已存在并已安装的DOM节点的引用(在本例中,该引用将为

If you're looking for a way to control the contents of an <iframe> via React in a de-facto canonical way, Portals are the way to go. And as with all things Portal: Once you establish a reference to an extisting and mounted DOM node (in this case that would be the contentWindow of a given <iframe>) and create a Portal with it, its contents are also considered children of the «parent» virtual DOM, which means a shared (synthetic) event system, contexts and so on.

请注意,为了简化代码,以下示例使用了可选的链接运算符, 在撰写本文时,并非所有浏览器都支持该功能.

Please note that, for code brevity, the examples below make use of the Optional chaining operator, which as of this writing is not supported in all browsers.

示例:一个功能性的React组件,包括钩子:

Example: A functional React component including hooks:

// iframe.js

import React, { useState } from 'react'
import { createPortal } from 'react-dom'

export const IFrame = ({
  children,
  ...props
}) => {
  const [contentRef, setContentRef] = useState(null)
  const mountNode =
    contentRef?.contentWindow?.document?.body

  return (
    <iframe {...props} ref={setContentRef}>
      {mountNode && createPortal(children, mountNode)}
    </iframe>
  )
}

示例:一个React类组件:

Example: A React class component:

// iframe.js

import React, { Component } from 'react'
import { createPortal } from 'react-dom'

export class IFrame extends Component {
  constructor(props) {
    super(props)
    this.state = {
      mountNode: null
    }
    this.setContentRef = (contentRef) => {
      this.setState({
        mountNode: contentRef?.contentWindow?.document?.body
      })
    }
  }

  render() {
    const { children, ...props } = this.props
    const { mountNode } = this.state
    return (
      <iframe
        {...props}
        ref={this.setContentRef}
      >
        {mountNode && createPortal(children, mountNode)}
      </iframe>
    )
  }
}

用法:

import { IFrame } from './iframe'

const MyComp = () => (
    <Frame>
        <h1>Hello Content!</h1>
    </Frame>
)

例如,可以轻松实现对<iframe> s <head>内容的进一步控制. 此要点显示.

Further control, for example over an <iframe>s <head> contents, can easily be achieved as this Gist shows.

还有 react-frame-component ,imho可以提供很多的软件包 在React中使用受控<iframe>时需要的一切.

There is also react-frame-component, a package that imho offers pretty much everything you need when working with controlled <iframe>s in React.

注意事项:

  • 此答案仅针对用例,其中给定<iframe>的所有者希望以React-ish方式以编程方式控制(如决定)其内容.
  • 此答案假设<iframe>的所有者符合有意义的标题属性.
  • This answer only addresses use cases, where the owner of a given <iframe> wants to programmatically control (as in decide about) its contents in a React-ish way.
  • This answer assumes, that the owner of an <iframe> complies to the Same-origin policy.
  • This answer is not suited to track how and when external resources are loaded in an <iframe src="https://www.openpgp.org/> kind of scenario.
  • If accessibility is something you care about, you should give your iframes meaningful title attributes.

用例(我知道);

  • OP的用例:广告以及控制其访问方式和何时可以访问您网站上安全范围内的元素的需求.
  • 可嵌入的第三方小部件.
  • 我的用例(因此是我对此事有一定了解的立场):CMS UI,您要在其中允许用户预览范围内的CSS样式,包括应用的媒体查询.

将一组给定的CSS样式(或样式表)添加到受控的<iframe>:

Adding a given set of CSS styles (or stylesheets) to a controlled <iframe>:

正如一位评论作者所指出的那样,在父应用程序和受控的<iframe>内容之间管理样式可能非常棘手. 如果您很幸运地拥有一个专用CSS文件,其中包含了<iframe>的所有必要视觉指示,那么仅 向您的IFrame组件传递引用所述样式的<link>标记,即使这不是处理<link> refs的最标准兼容方式:

As one comment author pointed out, managing styles between a parent application and the contents of a controlled <iframe> can be quite tricky. If you're lucky enough to have (a) dedicated CSS file(s) incorporating all necessary visual instructions for your <iframe>, it might suffice to just pass your IFrame component a <link> tag referencing said style(s), even though this is not the most standard compliant way to go about <link>refs:

const MyComp = () => (
  <Frame>
    <link rel="stylesheet" href="my-bundle.css">
    <h1>Hello Content!</h1>
  </Frame>
) 

然而,在当今时代,尤其是在React世界中,构建设置通常会动态创建样式和样式表: 因为它们利用了SASS之类的元语言,甚至利用了CSS-in-JS之类的更复杂的解决方案(样式化组件情感).

In this day and age however, and especially in a React world, most of the time, build setups create styles and stylesheets on the fly: Because they leverage meta-languages like SASS or even more involved solutions like CSS-in-JS stuff (styled-components, emotion).

此沙箱包含有关如何在React中将一些较流行的样式策略与iframe集成的示例.

This sandbox contains examples on how to integrate some of the more popular styling strategies with iframes in React.

https://codesandbox.io/s/react-iframe-examples-36k1x

这个答案过去也给出了关于16.3之前的React版本的配方.不过,在目前情况下,我认为可以肯定地说, 我们能够推出一个React版本,其中包括Portal,并在较小程度上引入了钩子.如果您需要有关iframe和React版本<的解决方案, 16 打我,我很乐意提供建议.

This answer used to also give recipes with regards to versions of React prior to 16.3. At this point in time however, I think it's safe to say that most of us are able to pull off a React version including Portals, and, to a lesser extent, hooks. If you're in need of solutions with regards to iframes and React versions < 16, hit me up, I'll gladly offer advice.

这篇关于如何设置React组件的iframe内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆