跨域iframe调整大小

Pio*_*ula 85 html css scripting iframe cross-domain

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

-编辑

向下滚动查看某些解决方案..或阅读如何不执行此操作:D

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

为了节省您的时间,请不要只使用sendMessages进行跨域通信. 我使用HTML <5的插件 - 转到底部以获得一个很好的例子:)


过去几天,我一直在尝试将iframe集成到网站中.这是一个短期解决方案,而另一方开发和API(可能需要几个月......)因为这是短期解决方案,我们想要使用easyXDM-我可以访问其他域,但很难让他们要求添加p3p标头,因为它是.....

3个iframe

我找到的最接近的解决方案是3个iframe - 但它是精神上的铬和野生动物园,所以我不能使用它.

用铬打开

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

测量滚动条

我发现了另一篇关于如何使用scrollheight尝试调整表单大小的文章..理论上它运作良好但我无法使用iframes滚动高度正确应用它.

document.body.scrollHeight
Run Code Online (Sandbox Code Playgroud)

该obvoisly使用身体高度(不能访问这些属性100%是基于客户端显示canvaz而不是x-domains文档高度)

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

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight
Run Code Online (Sandbox Code Playgroud)

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

计算样式

但是如果我在iframe的chrome中检查和元素,那么bladdy会向我展示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/ <-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>
Run Code Online (Sandbox Code Playgroud)

在调用者域上,他们只需要在同一个地方添加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>
Run Code Online (Sandbox Code Playgroud)

我修改了它发送的参数.如果您希望宽度正常工作,那么另一个域上的页面需要在一个类似于以下内容的样式中包含页面的宽度:

<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>
Run Code Online (Sandbox Code Playgroud)

这对我很有用.如果不包括宽度,那么框架表现得有点奇怪,并且有点试图猜测它应该是什么......并且如果你需要它也不会缩小.

方案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>
Run Code Online (Sandbox Code Playgroud)

如果尺寸发生变化,则可以更有效地查询间隔,只有在尺寸发生变化时才发送,而不是每隔500毫秒发送一次消息.如果您执行此检查,那么您可以将轮询更改为低至50毫秒!玩得开心


跨浏览器工作并且速度很快.很棒的调试功能!!

Excellent Work to  Sean Kinsey  who made the script!!!
Run Code Online (Sandbox Code Playgroud)

解决方案2(工作但不是很好)

所以基本上如果你与其他域有共同协议,那么你可以添加一个库来处理sendmessage.如果你没有任何访问权限,那么继续寻找更多的黑客攻击 - 因为我无法找到或完全证明我发现的这些内容.

所以其他域将包含这些头标记

<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>
Run Code Online (Sandbox Code Playgroud)

在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 );
  });
Run Code Online (Sandbox Code Playgroud)

而且您的页面将完成所有艰苦的工作,并有一个很好的脚本......

  //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');
     });
Run Code Online (Sandbox Code Playgroud)

方案3

它们现在是一个用于管理调整跨域iFrame大小的小型JS库,它仍然需要iFrame中有一些JavaScript,但是,这只是2.8k(765字节Gzip)本机JS,没有任何依赖并且在父页面调用之前它不会执行任何操作.这意味着它在其他人系统上是一个不错的客人.

此代码使用mutationObserver来检测DOM更改,并查找resize事件,以便iFrame保持内容大小.适用于IE8 +.

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

小智 24

与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
Run Code Online (Sandbox Code Playgroud)

在父窗口中,添加此代码.将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>
Run Code Online (Sandbox Code Playgroud)

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

最好,贝克


Sea*_*sey 10

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

所以,要么你这样做postMessage(适用于所有现代浏览器),要么花5分钟调整easyXDM中的resize iframe示例.

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


Dav*_*haw 6

看了很多不同的解决方案后,我最终编写了一个简单的小型库来记录一些不同的用例.由于我需要一个支持门户网站页面上多个用户生成的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
        );
    }
});
Run Code Online (Sandbox Code Playgroud)