跨网域iframe调整大小


85

如何从其他域调整iframe的大小

-编辑

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

经过数小时的代码黑客攻击后,得出的结论是,iframe内部的任何内容都无法访问,即使是在我的域中呈现的滚动条也是如此。我尝试了许多技巧都无济于事。

为了节省您的时间,甚至不要走这条路,只需使用sendMessages进行跨域通信。 我使用了HTML <5的插件-进入底部找到一个好例子:)


过去几天,我一直在尝试将iframe集成到网站中。这是一个短期解决方案,而另一方正在开发和API(可能要花费数月的时间...),并且因为这是短期解决方案,所以我们确实想使用easyXDM-我可以访问其他域,但要求他们这样做非常困难按原样添加p3p标头.....

3个iframe

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

镀铬

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

测量滚动条

我找到了另一篇有关如何使用scrollheight尝试调整表单大小的文章。理论上它可以正常工作,但是我无法使用iframe滚动高度正确应用它。

document.body.scrollHeight

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

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

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight

返回不同的Chrome值,即-或根本没有任何意义。问题是框​​架内的所有内容都被拒绝-甚至滚动条...

计算样式

但是,如果我检查并在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引擎可以查看源代码并根据源文件重新呈现页面。但这需要破解这些jscript ..对于商业实体而言,那不是理想的情况...以及一些涉及纯Java小程序或服务器端渲染的发票

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

http://htmlunit.sourceforge.net/ <-java而不是jscript

http://maxq.tigris.org/


编辑09-2013 更新

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

解决方案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>

在调用者域上,他们只需要在同一位置添加intermiedate_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毫秒发布一次消息,才发送间隔。如果执行此检查,则可以将轮询更改为低至50ms!玩得开心


跨浏览器工作并且速度很快。强大的调试功能!

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

解决方案2(可行,但效果不佳)

因此,基本上,如果您与其他域有共同的协议,则可以添加一个库来处理sendmessage。如果您无权访问另一个域,请继续寻找更多的hacks,因为我找不到或完全证明我找到的这些hacks。

因此其他域将在其中包含这些标签

<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(Gzipped 765字节压缩)本机JS,没有任何依赖关系。并且在父页面调用之前,它不会执行任何操作。这意味着它是其他人系统上的好客人。

这段代码使用mutationObserver来检测DOM的变化,还可以查找调整大小的事件,从而使iFrame的大小与内容保持一致。适用于IE8 +。

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


4
在easyXDM例子其实有很多更少的代码,不依赖于外部库,并在旧的浏览器工作:)是的,我有偏见,因为我是作者,但仍..
肖恩·金赛

我尝试了easyXDM,但无法在内部框架中浏览到其他链接以进行工作..我在寻找示例..有些链接中断了,示例页面无法清除..确实起作用了!这是我最初的答案..但是我用了这个。您能张贴一种内部浏览的方法吗?。我看了看..
Piotr Kula

@ppumkin下载随附的示例完全支持内部浏览。断开的链接可能是一个实验我做了,但是服务器得到了在一个点上刷新..
肖恩·金赛

1
是的,看了看,然后看了看:D出于某种原因,我无法使其在我的网站上正常工作。我会再试一次。
Piotr Kula

1
它有效-但是,如果我单击该域上的链接,它将与您的图书馆一起重新加载页面-但我无法收到任何消息。无论来自何处,我如何使它接受请求。这个easyxdm.swf是做什么用的?:)
Piotr Kula

Answers:


10

事实是-除了使用跨域消息传递,别无其他方法,因为您需要获取从一个域中的文档到另一域中的文档的计算高度。

因此,您可以使用postMessage(在所有现代浏览器中都可以使用)执行此操作,或者花费5分钟从easyXDM调整大小iframe示例

另一方实际上只需要将几个文件复制到其域中,并在其文档中添加一行代码即可。


相反,我的朋友。我找到了一种方法,可以将iframe的大小从跨doimain页面调整为iframe文档大小,并且没有滚动条。它有点hacky,但稍后会发布..它是如此简单,令人难以置信。
Piotr Kula

是的...我使用了sendmessage jquwery插件,尽管我发现了另一个hack-误报..;)谢谢!
Piotr Kula

好吧,有时候最好的办法就是听你的同龄人-发现其他人没有的魔法技巧的几率很小:)
肖恩·金西

想象一下,如果我做到了-纯粹是碰碰运气-太棒了。但是,:a谢谢
Piotr Kula,

没错-如果没有别的,您至少已经尝试过,尝试过,甚至还学到了新的东西:)
肖恩·金西

25

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

这是我的代码和David解决方案的结合。我的解决方案专门针对调整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 +“ |” var2。在父级上,您只需要在|上拆分字符串即可。并取回2个变量
dbonneville

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

1
如果我无法访问远程域该怎么办?谢谢
Bala Peterson

@BalaPeterson,如果您无法访问远程域,则由于浏览器中的安全限制,您将无法执行此操作。
大卫·布拉德肖

0

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

$(window).height();

并将其用作iframe高度属性。

好吧,结果是...

我们将永远不会拥有“页面”滚动,只有“ iframe”滚动。导航时,滚动条是谁都没有关系,但重要的是只有1。

好吧,这是一个问题,用户在导航时只需调整窗口大小即可。为了解决这个问题,我使用:

setInterval(getDocHeight, 1);

您是否认为该解决方案会导致任何错误?它为我工作,在iFrame上,我有php生成的动态连接。我担心将来会出现错误...


2
当然,“ iframe”滚动将始终具有与页面相同的尺寸。因此,在导航时,您只看到它,因为它是“页面”滚动。
艾尔顿·莫赖斯

0

如今,我只知道4种解决方案:

只有第三个可以解决许多问题。例如,您可以创建响应式iFrame;从内部将其关闭,或者您可以与其通信。但要做到这一点,您需要使用iframe中的iFrame和“第三方Cookie”解决方法(可选)。

我创建了有关示例的文章:事件驱动的跨域iFrame


0

您是否研究了“适合对象”的HTML5属性?将视频/图像缩放到iframe,而不是缩放iframe(如果您抓取的中型图像的宽度最终为5,000像素,则效果很好)。“适合”选项(其他分别为“封面”和“填充”)使用信箱排序方法,在保留宽高比的同时适合源。对于在那里没有HTML5的浏览器来说,似乎有很多可用的polyfill。这是一个很棒的工具,但是Edge的一个错误使它与Microsoft的《 New Nightmare》不兼容大约一年了,现在: https //github.com/anselmh/object-fit

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


0

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

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

测试工作截图


-2

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

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

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

但是,仅当您在iframe中显示的页面位于同一域上时,此方法才有效。如果不是,则无法访问所需的信息。因此,访问被拒绝错误。


是的,我已经尝试过了。就像您说的一样,它在相同的域上也很好用。告诉我-浏览器最初计算高度时如何知道100%是多少?为什么我们也不能访问这些值?Chrome会以计算样式将其存储在iframe甚至x域中的每个页面上……
Piotr Kula

高度将根据其内容和属性进行计算。在渲染子级之前,元素的高度是不确定的。
MarioRicalde,2011年

我怎样才能得到渲染的值呢?像镀铬检查一样?
皮奥特·库拉

-1,因为这不适用于跨域,这是他要求的。
肖恩·金西

您无法获取值。该检查器可以具有“浏览器扩展”级别的权限,而不具有“具有不同来源的网页”级别的权限。
昆汀

-2

要调整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和头部中的脚本名称,然后中提琴!您在同一页面上有多个调整大小...效果很好!

有朋。


我认为您没有解决所提出的实际问题。
Andrew Barber

是的,这是纯JavaScript,可以在同一域上调整iframe的大小。以任何方式使用jQuery都容易得多。这将无法跨站点工作,并且这里没有任何花哨的内容。而且没有php脚本这样的东西吗?
Piotr Kula 2014年
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.