在ReactJS中将iframe高度设置为scrollHeight

时间:2017-02-04 16:47:18

标签: javascript css reactjs iframe reactive-programming

  • 问题的典型解决方案因为没有在React中工作 它动态生成的组件结构和事件模型,而不是 传统的静态HTML:

脚本:

<script>
  function resizeIframe(obj) {
    obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
  }
</script>

HTML:

<iframe src="..." frameborder="0" scrolling="no" onload="resizeIframe(this)" />
  • 有一个npm包react-iframe,但它看起来未完成 (仅接受道具urlwidthheight):

    https://www.npmjs.com/package/react-iframe

  • 解决方案的可能部分是收听load事件 iframe,但与React兼容。

React中是否有办法将iframe的高度设置为其可滚动内容的高度?

我的代码:

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import Iframe from 'react-iframe'

export default class FullheightIframe extends Component {

    componentDidMount() {
        console.log("IFRAME DID MOUNT");
    }

    renderReactFrame() {
        return (
            <Iframe url="http://www.example.com" width="100%" height="100%" onLoad={()=>{console.log("IFRAME ON LOAD")}}></Iframe>
        );
    }

    renderHTMLFrame() {
        return (
            <iframe 
                onLoad={(loadEvent)=>{
                    // NOT WORKING var frameBody = ReactDOM.findDOMNode(this).contentDocument.body; // contentDocument undefined
                    // NOT WORKING obj.nativeEvent.contentWindow.document.body.scrollHeight // contentWindow undefined
                }} 
                ref="iframe" 
                src="http://www.example.com" 
                width="100%" 
                height="100%" 
                scrolling="no" 
                frameBorder="0"
            />
        );
    }

    render() {
        return (
            <div style={{maxWidth:640, width:'100%', height:'100%', overflow:'auto'}}>
                {this.renderHTMLFrame()}
            </div>
        );
    }
}

5 个答案:

答案 0 :(得分:5)

这是答案,但前两个重要的事情。

  • iframe必须是render()方法
  • 中的根组件
  • 必须从onLoad事件中捕获高度(如果满载,则为iframe)

以下是完整代码:

import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'

export default class FullheightIframe extends Component {

    constructor() {
        super();
        this.state = {
            iFrameHeight: '0px'
        }
    }

    render() {
        return (
            <iframe 
                style={{maxWidth:640, width:'100%', height:this.state.iFrameHeight, overflow:'visible'}}
                onLoad={() => {
                    const obj = ReactDOM.findDOMNode(this);
                    this.setState({
                        "iFrameHeight":  obj.contentWindow.document.body.scrollHeight + 'px'
                    });
                }} 
                ref="iframe" 
                src="http://www.example.com" 
                width="100%" 
                height={this.state.iFrameHeight} 
                scrolling="no" 
                frameBorder="0"
            />
        );
    }
}

答案 1 :(得分:2)

您要做的是在componentDidMount中,运行脚本来设置高度。 [如果要加载外部内容,可能需要在IFrame上添加事件侦听器,以等待加载外部内容。]

   componentDidMount() {
       const obj = ReactDOM.findDOMNode(this);
       obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
    }

还有另一个,更多的反应&#34;这样做的方式 - 你将把高度存放在哪里。

   componentDidMount() {
       const obj = ReactDOM.findDOMNode(this);
       this.setState({iFrameHeight:  obj.contentWindow.document.body.scrollHeight + 'px'});
    }

然后在你的渲染中:

render() {
    return (
        <div style={{maxWidth:640, width:'100%', height:this.state.iFrameHeight, overflow:'auto'}}>
            {this.renderHTMLFrame()}
        </div>
    );
}

答案 2 :(得分:1)

迄今为止提出的答案都没有为我工作。从setTimeout种类中做出简短onLoad的hackish方法似乎可以完成这项工作,至少在我的情况下如此。

class SmartIFrame extends React.Component {
    render() {
        return <iframe srcDoc={this.props.srcDoc}
                       scrolling="no"
                       frameBorder={0}
                       width="100%"
                       onLoad = {e => setTimeout(() => {
                           const obj = ReactDOM.findDOMNode(this);
                           obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
                       }, 50)}/>
    }
}

答案 3 :(得分:1)

这里需要注意几点:

  • 您可以使用参考来获取对iframe的引用,而不必搜索它
  • 使用iframe中的onLoad()处理程序确保在尝试调整内容之前已加载内容 - 如果您尝试使用React的生命周期方法(如componentDidMount()),则会冒内容不存在的风险爱好。
  • 您可能还需要一个调整大小处理程序来确保iframe根据需要调整大小 - 只需确保在卸载组件时将其清理。
  • 您必须小心不同浏览器报告高度的方式。去找你能找到的最大的。
  • 如果iframe内容与您的代码位于不同的域中,则可能会出现问题。有一些解决方案,例如react-iframe-resizer-super,试图以跨域兼容的方式解决此问题。

class WrappedFrame extends React.Component {
  state = { contentHeight: 100 };

  handleResize = () => {
    const { body, documentElement } = this.container.contentWindow.document;
    const contentHeight = Math.max(
      body.clientHeight,
      body.offsetHeight,
      body.scrollHeight,
      documentElement.clientHeight,
      documentElement.offsetHeight,
      documentElement.scrollHeight
    );
    if (contentHeight !== this.state.contentHeight) this.setState({ contentHeight });
  };
  
  onLoad = () => {
    this.container.contentWindow.addEventListener('resize', this.handleResize);
    this.handleResize();
  }
  
  componentWillUnmount() {
    this.container.contentWindow.removeEventListener('resize', this.handleResize);
  }
  
  render() {
    const { contentHeight } = this.state;
    return (
      <iframe
        frameBorder="0"
        onLoad={this.onLoad}
        ref={(container) => { this.container = container; }}
        scrolling="no"
        src="your.source"
        style={{ width: '100%', height: `${contentHeight}px` }}
        title="Some Content"
      />
    );
  }
}

在此示例中,我们将确定的内容高度存储在组件的状态中,并使用该状态设置渲染的iframe的高度。此外,通过将onLoad()处理程序定义放在组件中,可以在render()中保存一点性能,方法是不在每次重新渲染时创建新的处理函数。

答案 4 :(得分:1)

此npm软件包将执行您的操作,它提供了多种不同的方法来计算iframe中内容的高度

https://www.npmjs.com/package/iframe-resizer-react

在此用例中,可以按以下方式进行配置

<IframeResizer
    heightCalculationMethod="bodyScroll"
    src="http://anotherdomain.com/iframe.html"
/>