是否可以使用跨网域iframe高度自动调整大小功能?


110

我尝试了一些解决方案,但没有成功。我想知道是否有一种解决方案,最好是提供一个易于遵循的教程。


2
您尝试过哪些解决方案不成功?
伊兹密尔·拉米雷斯

1
我尝试了此操作,但是如文章中所述,它在webkit浏览器中表现不佳css-tricks.com/cross-domain-iframe-resizing还有另一个,但我不记得该URL。
J82


这回答了你的问题了吗?调整宽度和iframe的高度以适应内容在它
缩写

Answers:


68

您有三种选择:

1.使用iFrame调整大小

这是一个简单的库,用于根据内容调整iFrame的大小。它使用PostMessage和MutationObserver API,并具有IE8-10的后备功能。它还为内容页面提供了一些选项,以请求所包含的iFrame为特定大小,并且在完成操作后也可以关闭iFrame。

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

2.使用Easy XDM(PostMessage + Flash组合)

Easy XDM使用了一系列技巧来启用许多浏览器中不同窗口之间的跨域通信,并且有一些示例可用于将其用于iframe调整大小:

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通过在现代浏览器上使用PostMessage以及基于Flash的解决方案作为旧版浏览器的后备来工作。

另请参见Stackoverflow上的该线程(还有其他线程,这是一个常见问题)。而且,Facebook似乎也会使用类似的方法

3.通过服务器进行通讯

另一种选择是将iframe高度发送到您的服务器,然后使用JSONP从父网页从该服务器进行轮询(或在可能的情况下使用长轮询)。


1
对于PostMessage,如果您已经在使用jQuery,则可能还需要研究Ben Alman出色的postMessage插件:benalman.com/projects/jquery-postmessage-plugin
rinogo 2013年

8
iFrame调整程序需要访问托管iframe内容的服务器。因此,您只能将其用于您控制的域。
Hokascha

好收获,@ Hokascha。该项目声称支持跨域iframe,但阅读该文档后发现它仍然需要服务器访问嵌入式域。
–StockB

1
没有这些“替代品”是对这一问题的解决方案的实际。询问者希望从他们无法控制的网站设置跨域iFrame的iFrame高度。1.需要服务器访问。2.需要我认为较差的软件。Easy XDM的创建与10年前一样。从2019年开始的最新版本需要Flash。幸运的是,Flash已经死了,没有人可以依靠它。3.需要服务器访问。
redanimalwar

26

我得到了根据其内容动态设置iframe高度的解决方案。这适用于跨域内容。有一些步骤可以实现。

  1. 假设您已在“ abc.com/page”网页中添加了iframe

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

  2. 接下来,您必须在网页“ abc.com/page”下绑定Windows“ message”事件

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);        
    }
});

在iframe加载时,您必须使用“ FrameHeight”消息将消息发送到iframe窗口内容:

function setIframeHeight(ifrm) {
   var height = ifrm.contentWindow.postMessage("FrameHeight", "*");   
}
  1. 在iframe下添加到此处的主页面“ xyz.pqr / contactpage”上,您必须绑定窗口“ message”事件,该事件将要从“ 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 }, "*");       
    }
});

3
顺利进行。谢谢堆!
Alex Leonov

简而言之,这是我能找到的最技术性的方法,干得好@sudhir,谢谢:)
java acm

14

我所做的是比较iframe scrollWidth直到它更改了大小,同时我逐渐设置了iframe高度。它对我来说很好。您可以将增量调整为所需的任何值。

   <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>

4
您可能想对循环数添加上限,否则“ while”会退化为无限循环。
凯文·塞弗特

1
这使我的页面崩溃。
DDDD

好的简单解决方案。但是在我的想法中,尺寸的增加是由屏幕尺寸决定的。
Zeta

1

我有一个脚本,可将其内容放入iframe中。它还可以确保iFrameResizer存在(将其作为脚本注入),然后进行调整大小。

我将在下面提供一个简化的示例。

// /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();
    }    
}())

然后,可以使用以下脚本将iframe内容注入到另一个页面/网站内的任意位置:

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

iframe内容将在您放置脚本代码的位置下方注入。

希望这对某人有帮助。👍


好的,我添加<script ... data-src="http://google.com">了iframe src并将其填充。
BananaAcid

撰写本文时,当前版本是iframe-resizer@4.2.10
BananaAcid

1
...延伸到一个完整可用的例子codesandbox.io/s/remote-embed-ifrm-qdb74
BananaAcid

@BananaAcid-您的codeandbox链接不再有效
ctrlplusb

感谢您提到它,链接变成了:codesandbox.io/s/remote-embed-ifrm-yz0xl。(注意:codesandbox使用多个页面“伪造”并且可能会挂起。重新加载可能会有所帮助)
BananaAcid

1

这是此页面上的简单解决方案。http://lab.ohshiftlabs.com/iframesize/

下面是它的工作原理;

在此处输入图片说明

基本上,如果您可以在其他域中编辑页面,则可以放置另一个属于服务器的iframe页面,以节省Cookie的高度。以一定的间隔读取更新时的cookie,以更新iframe的高度。就这些。

下载; http://lab.ohshiftlabs.com/iframesize/iframesizepost.zip

编辑:2019年12月

上面的解决方案基本上使用一个iframe内的另一个iframe,第三个iframe属于首页域,您可以使用将大小值保存到cookie的查询字符串将此页面称为本页面,外页则以一定间隔检查此查询。但这不是一个好的解决方案,因此您应该遵循以下方法:

在首页:

window.addEventListener("message", (m)=>{iframeResizingFunction(m)});

在这里,您可以检查m.origin它的来源。

在框架页面中:

window.parent.postMessage({ width: 640, height:480 }, "*")

虽然,请不要忘记这不是那么安全的方法。为了使其安全更新*值(targetOrigin)为您想要的值。请遵循文档:https : //developer.mozilla.org/en-US/docs/Web/API/Window/postMessage


1
这些链接现在已失效(404),并且答案中未概述内容。:(
StockB

1
链接仍然无效。404
Arslan Ameer

0

我找到了另一个使用PHP来获取iframe大小的Web开发服务器端解决方案。

首先是使用服务器脚本PHP通过内部函数来进行外部调用:(就像file_get_contentswith但curl和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>

您需要iframe_reserve使用简单的方法在div()下显示函数调用生成的html。echo curl_get_file_contents("location url iframe","activation proxy")

完成此操作后,只需使用内容div(iframe_reserve)的简单控制,就可以使用javascript使用body事件函数onload来占据iframe页面的高度

因此,我通常divHeight = document.getElementById("iframe_reserve").clientHeight;在屏蔽div容器(iframe_reserve)之后获取要在外部调用的页面的高度。在此之后,我们以其良好的高度加载了iframe。


0

我在工作中使用React时遇到了这个问题。基本上,我们有一些外部html内容,我们将它们保存到数据库的文档表中,然后在某些情况下(当您位于Documents数据集中时)插入到页面上。

因此,给定内n联(最多n可以包含外部html),我们需要设计一个系统,以在每个内联中的内容完全加载后自动调整每个内联的iframe的大小。在转动了一下轮子之后,这就是我最终要做的事情:

  1. message在我们的React应用程序的索引中设置一个事件侦听器,该事件侦听器将检查我们将从发送方iframe设置的特定密钥。
  2. 在实际呈现iframe的组件中,将外部html插入其中之后,我附加了一个<script>标签,该标签将等待iframe window.onload触发。一旦触发,我们就可以使用postMessage有关iframe ID,计算出的高度等信息将消息发送到父窗口。
  3. 如果原点匹配并且索引侦听器中的键已满足,请获取id我们在MessageEvent对象中传递的iframe 的DOM
  4. 一旦有了iframe,只需从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"
                )
            }
        }
    }}
/>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.