当 iframe 内容的高度发生变化时自动调整 iframe 高度(同域)

Posted

技术标签:

【中文标题】当 iframe 内容的高度发生变化时自动调整 iframe 高度(同域)【英文标题】:Auto resize iframe height when the height of the iframe contents change (same domain) 【发布时间】:2012-12-16 06:50:52 【问题描述】:

我正在页面内加载 iframe,iframe 内容的长度会不时更改。我已经实施了以下解决方案。但是高度是固定的,因为只有在 iframe.onload 时才会调用 dyniframesize。

是否可以不时调整 iframe 的大小以改变 iframe 的高度?

<iframe src ="popup.html" frameborder="0" margin margin frameborder="0" scrolling="auto" id="ifm" name="ifm" onload="javascript:dyniframesize('ifm');" ></iframe> 

function dyniframesize(down)  
var pTar = null; 
if (document.getElementById) 
pTar = document.getElementById(down); 
 
else 
eval('pTar = ' + down + ';'); 
 
if (pTar && !window.opera) 
//begin resizing iframe 
pTar.style.display="block" 
if (pTar.contentDocument && pTar.contentDocument.body.offsetHeight) 
//ns6 syntax 
pTar.height = pTar.contentDocument.body.offsetHeight +20; 
pTar.width = pTar.contentDocument.body.scrollWidth+20; 
 
else if (pTar.Document && pTar.Document.body.scrollHeight) 
//ie5+ syntax 
pTar.height = pTar.Document.body.scrollHeight; 
pTar.width = pTar.Document.body.scrollWidth; 
 
 
 
</script> 

【问题讨论】:

【参考方案1】:

据我所知,没有一种非常自然的方法可以做到这一点,但有一些选择。

setInterval()

您可以使用setInterval() 重复检查 iframe 的内容高度并在需要时进行调整。这很简单,但效率很低。

事件监听器

iframe 内容(以及高度)中的任何内容更改通常由某些事件触发。例如,即使您从 iframe 外部添加内容,“添加”也可能是由单击按钮触发的。这可能对您有用:Live demo here (click).

var myIframe = document.getElementById('myIframe');

window.addEventListener('click', resizeIframe);
window.addEventListener('scroll', resizeIframe);
window.addEventListener('resize', resizeIframe);

myIframe.contentWindow.addEventListener('click', resizeIframe);

function resizeIframe() 
  console.log('resize!');

变异观察者

此解决方案适用于所有最新的浏览器 - http://caniuse.com/mutationobserver

Live demo here (click).

这真的很简单,应该可以捕捉到相关的变化。如果没有,您可以将其与上面的事件侦听器解决方案结合使用,以确保更新!

var $myIframe = $('#myIframe');
var myIframe = $myIframe[0];

var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

myIframe.addEventListener('load', function() 
  setIframeHeight();

  var target = myIframe.contentDocument.body;

  var observer = new MutationObserver(function(mutations) 
    setIframeHeight();
  );

  var config = 
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true
  ;
  observer.observe(target, config);
);

myIframe.src = 'iframe.html';

function setIframeHeight() 
  $myIframe.height('auto');
  var newHeight = $('html', myIframe.contentDocument).height();
  $myIframe.height(newHeight);

荣誉奖:上溢/下溢事件。

Read about it here(有很多)。

see my demo here(在 IE 11 中不起作用!)。

这个很酷的解决方案,但它不再适用于 IE。可能可以对其进行调整,但我宁愿使用上述解决方案之一,即使对于旧版浏览器我不得不回退到 1 秒 setInterval,只是因为它比这个解决方案简单得多。

【讨论】:

使用 MutationObserver 时,在 webkit 中它会在图像加载完成之前触发,因此您必须检测添加/更改的 IMG 节点,然后将负载侦听器附加到它们。 @DavidBradshaw 最后一个选项似乎再次可行。【参考方案2】:

实际上,您应该通过访问父窗口并更改 iframe 的高度从 iframe 执行此操作。

因为 iframe 中的文档通常会更好地知道它的主体是否改变了它的大小(您实际上可以将它绑定到 body.onload 之类的东西,而不是使用间隔来检查 iframe 中是否发生了变化)。

【讨论】:

您能否详细说明一下身体如何“知道”它何时改变了它的大小? 如果你的 iframe 能够动态改变它的高度(比如从 ajax 请求中插入一些数据),你总是可以“注入”像 window.parent.document.getElementById('myframe').style 这样的代码.height = window.document.body.offsetHeight (或类似的东西)在从 ajax 插入数据之后。否则,您将只需要在 iframe 中的 body.onload 中使用此代码。 您的回答并不是建议“动态”调整大小。很明显,在进行 ajax 调用后必须手动调用更新函数。他希望它能够自我更新。 好吧,(IMO)你的解决方案对我来说似乎有点“肮脏”,而且也很明显。我只是建议了“正确的做法”(如我所见)。 我注意到第一个解决方案效率低下,为了完整性我将其包括在内。第二种解决方案干净简单。第三个很棒而且超级高效,但是很复杂。我一会儿再补充。我不会亲自对此投反对票,我只是指出您的答案与问题无关..我想您可能会很高兴知道这一点。【参考方案3】:

您可以使用自定义事件在iframe 和父级之间发出信号。

iframe

if (window.parent !== window) 
  window.oldIframeHeight = 0;
  window.setInterval(function() 
      var currentHeight = document.body.offsetHeight;
      if (currentHeight !== window.oldIframeHeight) 
          window.parent.postMessage(currentHeight.toString(), "*");
          window.oldIframeHeight = currentHeight;
      
  , 100)

然后,在父级中:

window.addEventListener("message", function (e) 
    var h = parseInt(e.data, 10);
    if (!isNaN(h)) 
        $('#iframe').height(h)
    
, false);

【讨论】:

【参考方案4】:

我编写了一个小型库,它使用了 mutationaObserver 和 eventListners,回退到 IE8-10 的 setInterval 并且适用于同域和跨域。它可以调整高度和宽度。

http://davidjbradshaw.github.io/iframe-resizer/

【讨论】:

由于页面的复杂性,仅对我有用。感谢您与社区分享。很好的例子。 =) +1【参考方案5】:

iFrame 视图

<script type="text/javascript">
    var height = $("body").outerHeight();
    parent.SetIFrameHeight(height);
</script>

主视图

<script type="text/javascript">
    SetIFrameHeight = function(height) 
        $("#iFrameWrapper").height(height);
    
</script>

【讨论】:

以上是关于当 iframe 内容的高度发生变化时自动调整 iframe 高度(同域)的主要内容,如果未能解决你的问题,请参考以下文章

页面嵌套iframe时,怎样让iframe高度根据自身内容高度自适应

调整跨域 iframe 高度的大小 [重复]

iframe的高度可以随内容的多少而变化吗

根据内容动态调整 iframe 高度

iframe 自动调整其高度以适应内容高度

将 iframe 内容高度设置为动态自动调整大小