web-dev-qa-db-ja.com

ReactJSでiframeの高さをscrollHeightに設定する

  • この問題の一般的な解決策は、従来の静的HTMLとは対照的に、動的に生成されたコンポーネント構造とイベントモデルのため、Reactでは機能しません。

脚本:

<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

  • 解決策の可能性のある部分は、loadiframeイベントをリッスンすることですが、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>
        );
    }
}
7
Peter G.

ComponentDidMountで、スクリプトを実行して高さを設定します。 [外部コンテンツをロードする場合は、IFrameにイベントリスナーを追加して、外部コンテンツがロードされるまで待機することをお勧めします。]

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

これを行う別の、より「反応性の高い」方法があります-高さを状態で保存します。

   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>
    );
}
3
flexicious.com

これが答えですが、最初の2つの重要なことです。

  • 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"
            />
        );
    }
}
9
Peter G.

ここで注意すべき点がいくつかあります。

  • Refを使用して、iframeを検索する代わりに、iframeへの参照を取得できます。
  • IFrameのonLoad()ハンドラーを使用して、コンテンツのサイズを変更する前にコンテンツが確実に読み込まれるようにします。componentDidMount()のようなReactのライフサイクルメソッドを使用しようとすると、コンテンツがまだ存在しないというリスクがあります。
  • また、必要に応じて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
Matt

これまでに提案された答えはどれも私にはうまくいきませんでした。少なくとも私の場合は、setTimeoutの種類の中から短いonLoadを実行するというハックなアプローチがその仕事をしているようです。

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)}/>
    }
}
1
KT.

このnpmパッケージは何をするか、iframeのコンテンツの高さを計算するさまざまな方法を提供します

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

このユースケースでは、次のように構成できます。

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