【问题标题】:cross-domain iframe resize跨域 iframe 调整大小
【发布时间】:2011-08-20 00:04:15
【问题描述】:

如何从另一个域调整 iframe 的大小

-编辑

向下滚动以获取一些解决方案.. 或阅读如何不这样做:D

经过数小时的代码破解 - 结论是 iframe 内的任何内容都无法访问,即使是在我的域上呈现的滚动条也是如此。我尝试了很多技术都无济于事。

为了节省您的时间,甚至不要走这条路,只需使用 sendMessages 进行跨域通信即可。 我使用了 HTML


过去几天我一直在尝试将 iframe 集成到网站中。这是一个短期解决方案,而另一方开发和 API(可能需要几个月...) 而且因为这是我们想要使用easyXDM的短期解决方案-我可以访问另一个域,但是要求他们按原样添加p3p标头已经足够困难了.....

3 个 iframe

我找到的最接近的解决方案是 3 个 iframe,但它是 chrome 和 safari 的一种,所以我不能使用它。

在 chrome 中打开

http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&height=1179

测量滚动条

我发现了另一篇关于如何使用滚动高度来尝试调整表单大小的帖子。理论上它效果很好,但我无法使用 iframe 滚动高度正确应用它。

document.body.scrollHeight

这显然使用了主体高度(无法访问这些属性 100% 是基于客户端显示画布而不是 x 域文档高度)

我尝试使用 jquery 来获取 iframe 高度

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight

返回值在 chrome 和 ie 中不同 - 或者根本没有意义。 问题是框​​架内的所有内容都被拒绝 - 甚至滚动条......

计算样式

但是,如果我检查 iframe 的 chrome 中的元素,它会向我显示 iframe 内的文档尺寸(使用 jquery x-domain 获取 iframe.heigh - 访问被拒绝) 计算出的 CSS

中没有任何内容

现在 chrome 是如何计算的呢? (编辑 - 浏览器使用其内置渲染引擎重新渲染页面以计算所有这些设置 - 但没有附加到任何地方以防止跨域欺诈......所以......)

HTML4

我阅读了 HTML4.x 的规范,它说应该有通过 document.element 公开的只读值,但通过 jquery 拒绝访问

代理框架

我沿着代理站点的路线返回并计算哪个可以..直到用户通过 iframe 登录并且代理获取登录页面而不是实际内容。还有一些调用页面两次是不可接受的

http://www.codeproject.com/KB/aspnet/asproxy.aspx

http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/

重新渲染页面

我没有走这么远,但是那里有 jscript 引擎,它们会查看源代码并根据源文件重新呈现页面。但这需要破解那些 jscripts.. 这对于商业实体来说不是一个理想的情况...... 以及一些引入纯 Java 小程序或服务器端渲染

http://en.wikipedia.org/wiki/Server-side_JavaScript

http://htmlunit.sourceforge.net/

http://maxq.tigris.org/


编辑 09-2013 更新

所有这些都可以通过 HTML5 套接字来完成。但是对于非 HTML5 投诉页面,easyXDM 是很好的后备方案。

解决方案 1 非常好的解决方案!

使用easyXDM

在您的服务器上,您以以下形式设置页面

<html>
<head>
<script src="scripts/easyXDM.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">

    var transport = new easyXDM.Socket(/** The configuration */{
    remote: "http://www.OTHERDOMAIN.com/resize_intermediate.html?url=testpages/resized_iframe_1.html",

    //ID of the element to attach the inline frame to
    container: "embedded",
    onMessage: function (message, origin) {
        var settings = message.split(",");
        //Use jquery on a masterpage.
        //$('iframe').height(settings[0]);
        //$('iframe').width(settings[1]);

        //The normal solution without jquery if not using any complex pages (default)
        this.container.getElementsByTagName("iframe")[0].style.height = settings[0];
        this.container.getElementsByTagName("iframe")[0].style.width = settings[1];
    }
});

</script>

</head>

<body>
    <div id="embedded"></div>
</body>

在调用者域中,他们只需要在同一个地方添加 intermediadate_frame html 和 easyXDM.js。像父文件夹一样 - 然后您可以访问相关目录或仅适合您的包含文件夹。

选项 1

如果您不想将脚本添加到所有页面,请查看选项 2!

然后他们可以在您需要调整大小的每个页面的末尾添加一个简单的 jscript。无需在每个页面中都包含 easyxdm。

 <script type="text/javascript">
            window.onload = function(){ parent.socket.postMessage( (parseInt(document.body.clientHeight)) + "," + ( document.body.clientWidth ) );  };
        </script>

我已经修改了它发送的参数。如果您希望宽度正常工作,则 otherdomain 上的页面需要将页面宽度包含在类似于以下内容的样式中:

<style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                background-color: rgb(75,0,85);
                color:white;
                width:660px
            }
            a {
            color:white;
            visited:white;
            }
        </style>

这对我很有用。如果不包括宽度,则框架的行为有点奇怪,并且有点试图猜测它应该是什么......并且如果你需要它不会缩小。

选项 2

修改中间帧以轮询更改

你的中间框架应该看起来像这样..

    <!doctype html>
<html>
    <head>

        <title>Frame</title>
        <script type="text/javascript" src="easyXDM.js">
        </script>
        <script type="text/javascript">
            var iframe;
            var socket = new easyXDM.Socket({
                //This is a fallback- not needed in many cases
                swf: "easyxdm.swf",
                onReady: function(){
                    iframe = document.createElement("iframe");
                    iframe.frameBorder = 0;
                    document.body.appendChild(iframe);
                    iframe.src = "THE HOST FRAME";
            iframe.onchange = messageBack();

                },
                onMessage: function(url, origin){
                    iframe.src = url;
                }
            });

            //Probe child.frame for dimensions.
            function messageBack(){
                socket.postMessage ( iframe.contentDocument.body.clientHeight + "," + iframe.contentDocument.body.clientWidth); 
            };

            //Poll for changes on children every 500ms.
            setInterval("messageBack()",500); 

        </script>
        <style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                width: 100%;
                height: 100%;
            }

            iframe {
                width: 100%;
                height: 100%;
                border: 0px;
            }
        </style>
    </head>
    <body>

    </body>
</html>

间隔可以更有效地检查大小是否发生变化,并且仅在尺寸发生变化时才发送,而不是每 500 毫秒发布一次消息。如果您实施此检查,那么您可以将轮询更改为低至 50 毫秒!玩得开心


跨浏览器工作,速度很快。很棒的调试功能!!

Excellent Work to  Sean Kinsey  who made the script!!!

解决方案 2(有效但效果不佳)

所以基本上,如果您与其他域有相互协议,那么您可以添加一个库来处理发送消息。如果您对其他域没有任何访问权限.. 继续寻找更多黑客 - 因为我找不到或完全证明我发现的这些。

所以其他域会将这些包含在 Head 标签中

<script src="scripts/jquery-1.5.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery.postmessage.min.js" type="text/javascript"></script>
<script src="scripts/club.js" type="text/javascript"></script>

在 club.js 中只是我为调整大小调用而进行的一些自定义调用,并且包含..

 $(document).ready(function () {   
    var parent_url = decodeURIComponent( document.location.hash.replace( /^#/, '' ) ),link;
//Add source url hash to each url to authorise callback when navigating inside the frame.Without this clicking any links will break the communication and no messages will be received
$('a[href]').each(function(){ 
     this.href = this.href + document.location.hash ;
});
//Get the dimensions and send back to calling page.
var h1 = document.body.scrollHeight;
var w1 = document.body.scrollWidth;
$.postMessage({ if_height: h1, if_width: w1 }, parent_url, parent );
  });

您的页面将完成所有艰苦的工作并有一个不错的脚本...

  //This is almost like request.querystring used to get the iframe data
  function querySt(param, e) {
         gy = e.split("&");
         for (i = 0; i < gy.length; i++) {
             ft = gy[i].split("=");
             if (ft[0] == param) {
                 return ft[1];
             }
         }
     }


     $(function () {
         // Keep track of the iframe dimensions.
         var if_height;
         var if_width;
         // Pass the parent page URL into the Iframe in a meaningful way (this URL could be
         // passed via query string or hard coded into the child page, it depends on your needs).
         src = 'http://www.OTHERDOAMIN.co.uk/OTHERSTARTPAGE.htm' + '#' + encodeURIComponent(document.location.href),
         // Append the Iframe into the DOM.
         iframe = $('<iframe " src="' + src + '" width="100%" height="100%" scrolling="no" frameborder="0"><\/iframe>').appendTo('#iframe');

         // Setup a callback to handle the dispatched MessageEvent event. In cases where
         // window.postMessage is supported, the passed event will have .data, .origin and
         // .source properties. Otherwise, this will only have the .data property.
         $.receiveMessage(function (e) {
             // Get the height from the passsed data.
             //var h = Number(e.data.replace(/.*if_height=(\d+)(?:&|$)/, '$1'));
             var h = querySt("if_height", e.data);
             var w = querySt("if_width", e.data);


             if (!isNaN(h) && h > 0 && h !== if_height) {
                 // Height has changed, update the iframe.
                 iframe.height(if_height = h);
             }
             if (!isNaN(w) && w > 0 && w !== if_width) {
                 // Height has changed, update the iframe.
                 iframe.width(if_width = w);
             }
             //For debugging only really- can remove the next line if you want
             $('body').prepend("Recieved" + h + "hX" + w + "w .. ");
             // An optional origin URL (Ignored where window.postMessage is unsupported).
           //Here you must put the other domain.com name only! This is like an authentication to prevent spoofing and xss attacks! 
         }, 'http://www.OTHERDOMAIN.co.uk');
     });

选项 3

他们现在是一个小型 JS 库,用于管理跨域 iFrame 的大小调整,它仍然需要 iFrame 中包含一些 JavaScript,然而,这只是 2.8k(765 字节 Gzipped)的原生 JS,没有有任何依赖关系,并且在父页面调用之前它不会做任何事情。这意味着它是其他人系统的好客人。

此代码使用 mutationObserver 检测 DOM 更改并注意调整大小事件,以便 iFrame 保持与内容大小一致。适用于 IE8+。

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

【问题讨论】:

  • easyXDM 示例的代码实际上要少得多,不依赖外部库,并且也可以在旧版浏览器中运行 :) 是的,因为我是作者,所以我有偏见,但仍然如此。 .
  • 我尝试了easyXDM,但我无法让内部框架浏览到其他链接以工作..我寻找示例..有些链接已损坏,示例页面未清除..确实工作!是我原来的答案..但我用了这个。你能发布一个内部浏览的方法吗..我看了又看..
  • @ppumkin example that ships 与下载完全支持内部浏览。断开的链接可能是我做的一个实验,但服务器在某一时刻被刷新了..
  • 是的,看了又看:D 由于某种原因,我无法让它与我的网站一起使用。我会再试一次。
  • 它可以工作-但是如果我单击该域上的链接,它会重新加载页面-与您一起使用库-但我无法收到任何消息。无论请求来自何处,我如何让它接受请求。这个 easyxdm.swf 有什么用? :)

标签: javascript html css iframe cross-domain


【解决方案1】:

您是否要查找 iframe 中包含的页面高度?我有一些 javascript 工作,它检查 iframe 内容的高度,然后将 iframe 的高度设置为内容的高度。

var Height = document.getElementById('iFrameId').contentWindow.document.body.scrollHeight;

document.getElementById('iFrameId').height = Height;

但是,这仅适用于您在 iframe 中显示的页面位于同一域中的情况。如果不是,您将无法访问所需的信息。因此,访问被拒绝错误。

【讨论】:

  • 是的,我已经试过了。它工作得很好......就像你说的那样在同一个域上......告诉我 - 浏览器在最初计算高度时如何知道 100% 是多少?为什么我们也不能访问这些值? Chrome 将其存储在 iframe 甚至 x 域中每个页面的计算样式中......
  • 高度是根据内容和它们拥有的属性来计算的。在渲染子元素之前,元素的高度是不确定的。
  • 那我怎样才能得到渲染的值呢?就像 chrome 中的检查一样?
  • -1 因为这不能跨域工作,这是他要求的。
  • 您无法获取值。检查员可以,因为它具有“浏览器扩展”级别权限,而不是“具有不同来源的网页”级别权限。
【解决方案2】:

问题是 - 除了使用跨域消息传递之外别无他法,因为您需要从一个域中的文档到不同域中的文档获取计算高度。

因此,您要么使用postMessage(适用于所有现代浏览器)执行此操作,要么花5 分钟从easyXDM 调整resize iframe example

对方真的只需要复制几个文件到他们的域中,然后在他们的文档中添加一行代码..

【讨论】:

  • 相反,我的朋友。我找到了一种将 iframe 从跨域页面调整为 iframe 文档大小且没有滚动条的方法。它有点骇人听闻,但稍后会发布。它就是这么简单,令人难以置信。
  • 是的...我使用了 sendmessage jquwery 插件-尽管我发现了另一个 hack-误报.. ;) 感谢您的好提示!
  • 嗯,有时最好的办法是倾听你的同行 - 你发现一些其他人没有的神奇技巧的几率非常小:)
  • 想象一下,如果我这样做了——纯粹的命中注定——会很棒。但是是的-苗条:D 谢谢
  • 是的 - 如果没有别的,你至少已经尝试过,实验过,也许还学到了一些新东西 :)
【解决方案3】:

我没有在 iframe 上使用 scroll=no,而是将其更改为“自动”。然后,我得到实际窗口的大小

$(window).height();

并将其用作 iframe 高度属性。

嗯,结果是……

我们永远不会有“页面”滚动,只有“iframe”滚动。当您导航时,谁是卷轴并不重要,重要的是只有 1 个。

嗯,问题是用户在导航时只是简单地调整了窗口的大小。为了解决这个问题,我使用:

setInterval(getDocHeight, 1);

您是否认为该解决方案会导致任何错误?它对我有用,在 iFrame 上我有 php 生成的动态内容。我害怕将来会出现这样的错误......

【讨论】:

  • 当然,“iframe”滚动条总是与页面大小相同。因此,在导航时,您只会看到它是“页面”滚动。
【解决方案4】:

与 Sean 提到的类似,您可以使用 postMessage。我花了很多时间尝试不同的方法来调整跨域 iframe 的大小,但没有运气,直到我偶然发现了 David Walsh 的这篇很棒的博文:http://davidwalsh.name/window-iframe

这是我的代码和大卫的解决方案的组合。我的解决方案专门针对调整 iframe 的大小。

在子页面中,找到页面的高度并将其传递给父页面(其中包含 iframe)。将 element_id 替换为您的元素 id(html、body 等)。

<script>
function adjust_iframe_height(){
    var actual_height = document.getElementById('element_id).scrollHeight;
    parent.postMessage(actual_height,"*"); 
    //* allows this to post to any parent iframe regardless of domain
}
</script>

<body onload="adjust_iframe_height();"> 
//call the function above after the content of the child loads

在父窗口中,添加此代码。将 iframe_id 替换为您的 iframe ID:

<script>
// Create IE + others compatible event handler
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

// Listen to message from child window
eventer(messageEvent,function(e) {
  console.log('parent received message!:  ',e.data);
  document.getElementById('iframe_id').height = e.data + 'px';
},false);
</script>

如果您打开控制台,您将在控制台日志中看到正在打印的高度。这将帮助您进行调试,这就是我将其留在那里的原因。

最好, 贝克

【讨论】:

  • 这很好用,但在 IE 中效果不那么好。我必须发送 2 个变量,但如果它是数组或对象,IE 将不接受“数据”。但是,我只是将数据创建为 data = var1 + "|"变种 2。在父级上,您只需将字符串拆分为 |并取回你的 2 个变量。
【解决方案5】:

在寻找了很多不同的解决方案后,我最终编写了一个简单的小型库来考虑许多不同的用例。因为我需要一个在门户页面上支持多个用户生成的 iFrame 的解决方案,支持浏览器调整大小并且可以处理 iFrame 之后加载的主机页面 JavaScript。我还添加了对宽度大小和回调函数的支持,并允许覆盖 body.margin,因为您可能希望将此设置为零。

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

iframe 代码只是一小段独立的 JavaScript,因此它是其他人页面上的好客。

然后使用以下可用选项在主机页面上初始化脚本。

iFrameResize({
    log                    : true,  // For development
    autoResize             : true,  // Trigering resize on events in iFrame
    contentWindowBodyMargin: 8,     // Set the default browser body margin style (in px)
    doHeight               : true,  // Calculates dynamic height
    doWidth                : false, // Calculates dynamic width
    enablePublicMethods    : true,  // Enable methods within iframe hosted page 
    interval               : 32,    // interval in ms to recalculate body height, 0 to disable refreshing
    scrolling              : false, // Enable the scrollbars in the iFrame
    callback               : function(messageData){ // Callback fn when message is received
        $('p#callback').html(
            '<b>Frame ID:</b> '    + messageData.iframe.id +
            ' <b>Height:</b> '     + messageData.height +
            ' <b>Width:</b> '      + messageData.width + 
            ' <b>Event type:</b> ' + messageData.type
        );
    }
});

【讨论】:

  • 不错的家伙。绝对是很多人都会使用的东西! +1
  • 如果我无权访问远程域怎么办?谢谢
  • @BalaPeterson,如果你不能访问远程域,那么由于浏览器的安全限制,你不能这样做。
【解决方案6】:

要调整 iframe 的大小,这里有一个简单的脚本:

这在头脑中:(这是为 php 脚本编写的,对于 html,将 ' 更改为 " 并将 \" 更改为 '...

<script type='text/javascript'>
<!--
function resizeIframe(id){
/*
this.obj=obj
//this.obj.width=null
//this.obj.width=window.frames[\"sizeframe1\"].document.body.scrollWidth
this.obj.style.height=\"\" // for Firefox and Opera
setTimeout(\"this.obj.style.height=this.obj.contentWindow.document.body.scrollHeight+(notIE?heightOffset:0)\",10) // setTimeout required for Opera
*/

el=document.getElementById(id)
el.style.height='200px' // for Firefox and Opera
setTimeout('el.style.height=el.contentWindow.document.body.scrollHeight+\"px\"',1) // setTimeout required for Opera
}

// -->
</script>"

头尾

这在正文中(请记住,这是为 php 脚本编写的,对于 html,将所有 ' 更改为 " 并将 \" 更改为 '...)

<iframe onload='resizeIframe(this.id)' allowTransparency=\"true\" name='ccpaymentwindow' id='sizeframe1' marginwidth='1' marginheight='1' height='700' width='690' border='0' frameborder='1' scrolling='no' src='ccmslink.php?variable1=" . $variable1 . "'></iframe>

奖励:上面有一些提示。因为它是为 php 脚本设置的,所以你可以用它做很多事情......要了解更多,做更多......

关键是“sizeframe1”....对于同一页面上的多个“调整大小”,复制相同的脚本,但更改 iframe 中的 id 和头部脚本中的名称,中提琴!您在同一页面上有多个调整大小...效果很好!

请打。

【讨论】:

  • 我认为您没有解决所提出的实际问题。
  • 是的-这是纯 javascript 来调整同一域上的 iframe 的大小。以任何方式使用 jQuery 都容易得多。这不会跨站点工作,这里没有什么可以允许的。而且没有php脚本之类的东西?!
【解决方案7】:

目前我只知道 4 个解决方案:

只有第三种才能解决很多问题。例如您可以创建响应式 iFrame;从内部关闭它或您可以与它交流。但要做到这一点,您需要 iframe 中的 iFrame 和“第三方 cookie”解决方法(可选)。

我已经创建了一篇关于它的文章,例如:Event-driven cross-domain iFrame

【讨论】:

    【解决方案8】:

    您是否查看过“object-fit”HTML5 属性?将视频/图像缩放到 iframe,而不是缩放 iframe(如果您抓取最终宽度为 5,000 像素的中等大小的图像,那就太好了)。 “适合”选项(其他是“封面”和“填充”)使用一种信箱类型的方法来适应源,同时保留纵横比。对于那些没有 HTML5 的人来说,看起来有很多可用的 polyfills。这个很棒,但是 Edge 端的一个错误使它与 Microsoft 的 New Nightmare 不兼容大约一年,现在:https://github.com/anselmh/object-fit

    编辑:要解决跨域问题,您始终可以在 Chrome 扩展内容脚本中完成工作,因为它认为这是您粘贴 iframe 的页面的一部分。

    【讨论】:

      【解决方案9】:

      HTTPS 另一个链接获取 iframe 自动高度的高度

      https://-a.com内容:

       <!DOCTYPE html>
          <html>
          <head>
              <title>Test Page</title>
          </head>
          <body>
              Test Page:
              <hr/>
              <iframe id="iframe" src="https://-b.com" style="width:100%;min-height:600px;border:none;" scrolling="no" ></iframe>
              <script>
              // browser compatibility: get method for event 
              // addEventListener(FF, Webkit, Opera, IE9+) and attachEvent(IE5-8)
              var myEventMethod = 
                  window.addEventListener ? "addEventListener" : "attachEvent";
              // create event listener
              var myEventListener = window[myEventMethod];
              // browser compatibility: attach event uses onmessage
              var myEventMessage = 
                  myEventMethod == "attachEvent" ? "onmessage" : "message";
              // register callback function on incoming message
              myEventListener(myEventMessage, function (e) {
                  // we will get a string (better browser support) and validate
                  // if it is an int - set the height of the iframe #my-iframe-id
                  if (e.data === parseInt(e.data)) 
                      document.getElementById('iframe').height = e.data + "px";
              }, false);
              </script>
          </body>
          </html>
      

      https://-b.com iframe 内容:

      <!DOCTYPE html>
      <html>
      <head>
          <title>Test Iframe Content</title>
          <script type="text/javascript">
          // all content including images has been loaded
          window.onload = function() {
              // post our message to the parent
              window.parent.postMessage(
                  // get height of the content
                  document.body.scrollHeight
                  // set target domain
                  ,"*"
              )
          };
      </script>
      </head>
      <body>
      <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>1
      <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>2
      <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>3
      <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>4
      <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>5
      <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>6
      </body>
      </html>
      

      工作台:

      xcom http > ycom https 工作

      xcom https > ycom https 工作

      xcom http > ycom http 工作

      xcom https > ycom http 工作

      【讨论】:

        猜你喜欢
        • 2011-08-02
        • 1970-01-01
        • 2011-01-18
        • 1970-01-01
        • 2011-04-26
        • 2014-08-30
        • 2011-11-23
        • 1970-01-01
        相关资源
        最近更新 更多