Is there a cross-domain iframe height auto-resizer that works?

后端 未结 7 2359
暖寄归人
暖寄归人 2020-11-27 09:41

I tried a few solutions but wasn\'t successful. I\'m wondering if there is a solution out there preferably with an easy-to-follow tutorial.

相关标签:
7条回答
  • 2020-11-27 10:14

    You have three alternatives:

    1. Use iFrame-resizer

    This is a simple library for keeping iFrames sized to their content. It uses the PostMessage and MutationObserver APIs, with fall backs for IE8-10. It also has options for the content page to request the containing iFrame is a certain size and can also close the iFrame when your done with it.

    https://github.com/davidjbradshaw/iframe-resizer

    2. Use Easy XDM (PostMessage + Flash combo)

    Easy XDM uses a collection of tricks for enabling cross-domain communication between different windows in a number of browsers, and there are examples for using it for iframe resizing:

    http://easyxdm.net/wp/2010/03/17/resize-iframe-based-on-content/

    http://kinsey.no/blog/index.php/2010/02/19/resizing-iframes-using-easyxdm/

    Easy XDM works by using PostMessage on modern browsers and a Flash based solution as fallback for older browsers.

    See also this thread on Stackoverflow (there are also others, this is a commonly asked question). Also, Facebook would seem to use a similar approach.

    3. Communicate via a server

    Another option would be to send the iframe height to your server and then poll from that server from the parent web page with JSONP (or use a long poll if possible).

    0 讨论(0)
  • 2020-11-27 10:15

    What I did was compare the iframe scrollWidth until it changed size while i incrementally set the IFrame Height. And it worked fine for me. You can adjust the increment to whatever is desired.

       <script type="text/javascript">
        function AdjustIFrame(id) {
            var frame = document.getElementById(id);
            var maxW = frame.scrollWidth;
            var minW = maxW;
            var FrameH = 100; //IFrame starting height
            frame.style.height = FrameH + "px"
    
            while (minW == maxW) {
                FrameH = FrameH + 100; //Increment
                frame.style.height = FrameH + "px";
                minW = frame.scrollWidth;
            }
        }
    
       </script>
    
    
    <iframe id="RefFrame" onload="AdjustIFrame('RefFrame');" class="RefFrame"
        src="http://www.YourUrl.com"></iframe>
    
    0 讨论(0)
  • 2020-11-27 10:16

    I ran into this issue while working on something at work (using React). Basically, we have some external html content that we save into our document table in the database and then insert onto the page under certain circumstances when you're in the Documents dataset.

    So, given n inlines, of which up to n could contain external html, we needed to devise a system to automatically resize the iframe of each inline once the content fully loaded in each. After spinning my wheels for a bit, this is how I ended up doing it:

    1. Set a message event listener in the index of our React app which checks for a a specific key that we will set from the sender iframe.
    2. In the component that actually renders the iframes, after inserting the external html into it, I append a <script> tag that will wait for the iframe's window.onload to fire. Once that fires, we use postMessage to send a message to the parent window with information about the iframe id, computed height, etc.
    3. If the origin matches and the key is satisfied in the index listener, grab the DOM id of the iframe that we pass in the MessageEvent object
    4. Once we have the iframe, just set the height from the value that is passed from the iframe postMessage.
    // index
    if (window.postMessage) {
        window.addEventListener("message", (messageEvent) => {
            if (
                messageEvent.data.origin &&
                messageEvent.data.origin === "company-name-iframe"
            ) {
                const iframe = document.getElementById(messageEvent.data.id)
                // this is the only way to ensure that the height of the iframe container matches its body height
                iframe.style.height = `${messageEvent.data.height}px`
                // by default, the iframe will not expand to fill the width of its parent
                iframe.style.width = "100%"
                // the iframe should take precedence over all pointer events of its immediate parent
                // (you can still click around the iframe to segue, for example, but all content of the iframe
                // will act like it has been directly inserted into the DOM)
                iframe.style.pointerEvents = "all"
                // by default, iframes have an ugly web-1.0 border
                iframe.style.border = "none"
            }
        })
    }
    
    // in component that renders n iframes
    <iframe
        id={`${props.id}-iframe`}
        src={(() => {
            const html = [`data:text/html,${encodeURIComponent(props.thirdLineData)}`]
            if (window.parent.postMessage) {
                html.push(
                    `
                    <script>
                    window.onload = function(event) {
                        window.parent.postMessage(
                            {
                                height: document.body.scrollHeight,
                                id: "${props.id}-iframe",
                                origin: "company-name-iframe",
                            },
                            "${window.location.origin}"
                        );
                    };
                    </script>
                    `
                )
            }
    
            return html.join("\n")
        })()}
        onLoad={(event) => {
            // if the browser does not enforce a cross-origin policy,
            // then just access the height directly instead
            try {
                const { target } = event
                const contentDocument = (
                    target.contentDocument ||
                    // Earlier versions of IE or IE8+ where !DOCTYPE is not specified
                    target.contentWindow.document
                )
                if (contentDocument) {
                    target.style.height = `${contentDocument.body.scrollHeight}px`
                }
            } catch (error) {
                const expectedError = (
                    `Blocked a frame with origin "${window.location.origin}" ` +
                    `from accessing a cross-origin frame.`
                )
                if (error.message !== expectedError) {
                    /* eslint-disable no-console */
                    console.err(
                        `An error (${error.message}) ocurred while trying to check to see ` +
                        "if the inner iframe is accessible or not depending " +
                        "on the browser cross-origin policy"
                    )
                }
            }
        }}
    />
    
    0 讨论(0)
  • 2020-11-27 10:17

    I have a script that drops in the iframe with it's content. It also makes sure that iFrameResizer exists (it injects it as a script) and then does the resizing.

    I'll drop in a simplified example below.

    // /js/embed-iframe-content.js
    
    (function(){
        // Note the id, we need to set this correctly on the script tag responsible for
        // requesting this file.
        var me = document.getElementById('my-iframe-content-loader-script-tag');
    
        function loadIFrame() {
            var ifrm = document.createElement('iframe');
            ifrm.id = 'my-iframe-identifier';
            ifrm.setAttribute('src', 'http://www.google.com');
            ifrm.style.width = '100%';
            ifrm.style.border = 0;
            // we initially hide the iframe to avoid seeing the iframe resizing
            ifrm.style.opacity = 0;
            ifrm.onload = function () {
                // this will resize our iframe
                iFrameResize({ log: true }, '#my-iframe-identifier');
                // make our iframe visible
                ifrm.style.opacity = 1;
            };
    
            me.insertAdjacentElement('afterend', ifrm);
        }
    
        if (!window.iFrameResize) {
            // We first need to ensure we inject the js required to resize our iframe.
    
            var resizerScriptTag = document.createElement('script');
            resizerScriptTag.type = 'text/javascript';
    
            // IMPORTANT: insert the script tag before attaching the onload and setting the src.
            me.insertAdjacentElement('afterend', ifrm);
    
            // IMPORTANT: attach the onload before setting the src.
            resizerScriptTag.onload = loadIFrame;
    
            // This a CDN resource to get the iFrameResizer code.
            // NOTE: You must have the below "coupled" script hosted by the content that
            // is loaded within the iframe:
            // https://unpkg.com/iframe-resizer@3.5.14/js/iframeResizer.contentWindow.min.js
            resizerScriptTag.src = 'https://unpkg.com/iframe-resizer@3.5.14/js/iframeResizer.min.js';
        } else {
            // Cool, the iFrameResizer exists so we can just load our iframe.
            loadIFrame();
        }    
    }())
    

    Then the iframe content can be injected anywhere within another page/site by using the script like so:

    <script
      id="my-iframe-content-loader-script-tag"
      type="text/javascript"
      src="/js/embed-iframe-content.js"
    ></script>
    

    The iframe content will be injected below wherever you place the script tag.

    Hope this is helpful to someone.

    0 讨论(0)
  • 2020-11-27 10:27

    I found another server side solution for web dev using PHP to get the size of an iframe.

    First is using server script PHP to an external call via internal function: (like a file_get_contents with but curl and dom).

    function curl_get_file_contents($url,$proxyActivation=false) {
        global $proxy;
        $c = curl_init();
        curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($c, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7");
        curl_setopt($c, CURLOPT_REFERER, $url);
        curl_setopt($c, CURLOPT_URL, $url);
        curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
        if($proxyActivation) {
            curl_setopt($c, CURLOPT_PROXY, $proxy);
        }
        $contents = curl_exec($c);
        curl_close($c);
        $dom = new DOMDocument();
        $dom->preserveWhiteSpace = false;
        @$dom->loadHTML($contents);
        $form = $dom->getElementsByTagName("body")->item(0);
        if ($contents) //si on a du contenu
            return $dom->saveHTML();
        else
            return FALSE;
    }
    $url = "http://www.google.com"; //Exernal url test to iframe
    <html>
        <head>
        <script type="text/javascript">
    
        </script>
        <style type="text/css">
        #iframe_reserve {
            width: 560px;
            height: 228px
        }
        </style>
        </head>
    
        <body>
            <div id="iframe_reserve"><?php echo curl_get_file_contents($url); ?></div>
    
            <iframe id="myiframe" src="http://www.google.com" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"  style="overflow:none; width:100%; display:none"></iframe>
    
            <script type="text/javascript">
                window.onload = function(){
                document.getElementById("iframe_reserve").style.display = "block";
                var divHeight = document.getElementById("iframe_reserve").clientHeight;
                document.getElementById("iframe_reserve").style.display = "none";
                document.getElementById("myiframe").style.display = "block";
                document.getElementById("myiframe").style.height = divHeight;
                alert(divHeight);
                };
            </script>
        </body>
    </html>
    

    You need to display under the div (iframe_reserve) the html generated by the function call by using a simple echo curl_get_file_contents("location url iframe","activation proxy")

    After doing this a body event function onload with javascript take height of the page iframe just with a simple control of the content div (iframe_reserve)

    So I used divHeight = document.getElementById("iframe_reserve").clientHeight; to get height of the page external we are going to call after masked the div container (iframe_reserve). After this we load the iframe with its good height that's all.

    0 讨论(0)
  • 2020-11-27 10:33

    I got the solution for setting the height of the iframe dynamically based on it's content. This works for the cross domain content. There are some steps to follow to achieve this.

    1. Suppose you have added iframe in "abc.com/page" web page

      <div> <iframe id="IframeId" src="http://xyz.pqr/contactpage" style="width:100%;" onload="setIframeHeight(this)"></iframe> </div>

    2. Next you have to bind windows "message" event under web page "abc.com/page"

    window.addEventListener('message', function (event) {
    //Here We have to check content of the message event  for safety purpose
    //event data contains message sent from page added in iframe as shown in step 3
    if (event.data.hasOwnProperty("FrameHeight")) {
            //Set height of the Iframe
            $("#IframeId").css("height", event.data.FrameHeight);        
        }
    });
    

    On iframe load you have to send message to iframe window content with "FrameHeight" message:

    function setIframeHeight(ifrm) {
       var height = ifrm.contentWindow.postMessage("FrameHeight", "*");   
    }
    
    1. On main page that added under iframe here "xyz.pqr/contactpage" you have to bind windows "message" event where all messages are going to receive from parent window of "abc.com/page"
    window.addEventListener('message', function (event) {
    
        // Need to check for safety as we are going to process only our messages
        // So Check whether event with data(which contains any object) contains our message here its "FrameHeight"
       if (event.data == "FrameHeight") {
    
            //event.source contains parent page window object 
            //which we are going to use to send message back to main page here "abc.com/page"
    
            //parentSourceWindow = event.source;
    
            //Calculate the maximum height of the page
            var body = document.body, html = document.documentElement;
            var height = Math.max(body.scrollHeight, body.offsetHeight,
                html.clientHeight, html.scrollHeight, html.offsetHeight);
    
           // Send height back to parent page "abc.com/page"
            event.source.postMessage({ "FrameHeight": height }, "*");       
        }
    });
    
    0 讨论(0)
提交回复
热议问题