是否有一个跨域 iframe 高度自动调整工程?

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

117905 次浏览

你有三个选择:

1. 使用 iFrame-resizer

这是一个简单的库,可以根据内容保持 iFrame 的大小。它使用 PostMessage 和 MutationObserver API,并为 IE8-10提供后备。它还提供了内容页面的选项,以请求包含 iFrame 的内容是一定大小,并且当您使用完该内容页面时,还可以关闭 iFrame。

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

2. 使用易用 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/

EasyXDM 通过在现代浏览器上使用 邮政信息和基于 Flash 的解决方案作为老式浏览器的备用方案来工作。

参见 关于 Stackoverflow 的这个线程(还有其他的,这是一个常见的问题)。

3. 通过服务器进行交流

另一种选择是将 iframe 高度发送到服务器,然后使用 JSONP 从父网页轮询该服务器(或者如果可能的话使用长轮询)。

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

首先是使用服务器脚本 PHP 通过内部函数对外部调用进行调用: (像带有 but curl 和 dom 的 file_get_contents)。

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>

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

完成此操作后,使用 javascript 执行 body 事件函数,通过对 content div (iframe_reserve)的简单控制获取页面 iframe 的高度

因此,我使用 divHeight = document.getElementById("iframe_reserve").clientHeight;来获取在屏蔽了 div 容器(iframe_reserve)之后将要调用的外部页面的高度。之后,我们加载 iframe 的良好高度,这就是全部。

我所做的是比较 IFrame scrollWidth,直到它改变了大小,同时我增量设置了 IFrame Height。我觉得挺好的。您可以根据需要调整增量。

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

下面是一个替代实现。

enter image description here

基本上,如果你能够在其他域编辑页面,你可以放置属于你的服务器的另一个 iframe 页面,保存 Cookie 的高度。 使用更新时读取 cookie 的间隔,更新 iframe 的高度。

编辑: 2019年12月

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

首页:

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

在这里你可以检查 m.origin看看它是从哪里来的。

相框:

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

虽然,请不要忘记这不是那么安全的方式。使其具有所需值的 update * value (targetOrigin)安全。 请参阅文档: < a href = “ https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage”rel = “ nofollow norefrer”> https://developer.mozilla.org/en-us/docs/web/api/window/postmessage

我得到了根据内容动态设置 iframe 高度的解决方案。这适用于跨域内容。 要实现这一点,需要遵循一些步骤。

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

    < div > < iframe id = “ lframeId”src = “ http://xyz.pqr/contactpage”style = “ width: 100% ;”onload = “ setlframeheight (this)”>

  • 下一步你必须绑定在网页“ 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 加载时,您必须向 iframe 窗口内容发送带有“ FrameHeight”消息的消息:

    function setIframeHeight(ifrm) {
    var height = ifrm.contentWindow.postMessage("FrameHeight", "*");
    }
    
    1. 在主页上,在 iframe 下添加“ xyz.pqr/contactpage”,你必须绑定 windows“ 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 }, "*");
    }
    });
    

    我有一个脚本,可以在 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>
    

    无论您在哪里放置 script 标记,iframe 内容都会被注入到下面。

    希望这对某些人有帮助。

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

    因此,给定 n内联,其中到 n可以包含外部 html,我们需要设计一个系统来自动调整每个内联的 iframe 大小,一旦内容在每个内联中完全加载。转了一会儿后,我就这么做了:

    1. 在 React 应用程序的索引中设置一个 message事件监听器,它检查我们将从发送方 iframe 设置的特定键。
    2. 在实际呈现 iframe 的组件中,在将外部 html 插入其中之后,我将附加一个 <script>标记,该标记将等待 iframe 的 window.onload激发。一旦触发,我们使用 postMessage向父窗口发送一条消息,其中包含有关 iframe id、计算高度等信息。
    3. 如果原点匹配,并且索引侦听器中的键满足要求,那么获取我们在 MessageEvent对象中传递的 iframe 的 DOM id
    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"
    )
    }
    }
    }}
    />