首页 文章

跨域iframe调整大小

提问于
浏览
83

How do I resize an iframe from another domain

-编辑

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

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

To save you time don't even go down this route just use sendMessages for cross domain communications. 我使用HTML <5的插件 - 转到底部以获得一个很好的例子:)


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

3 iframes

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

用铬打开

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

Measure the scrollbars

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

document.body.scrollHeight

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

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

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight

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

Computed Styles

但是,如果我在iframe的chrome中检查和元素,那么bladdy会向我显示iframe中的文档维度(使用jquery x-domain获取iframe.heigh - 访问被拒绝)计算CSS中没有任何内容
enter image description here

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

HTML4

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

Proxy Frame

我走了代理网站的路线并计算哪个是好的..直到用户通过iframe登录并且代理获得登录页面而不是实际内容 . 对某些人来说,调用两次页面也是不可接受的

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

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

Re-Render the page

我没有走到这一步,但有一些jscript引擎会查看源代码并根据源文件重新呈现页面 . 但它需要黑客攻击那些jscripts ..这对商业实体来说不是一个理想的情况......而且有些人会把纯Java小程序或服务器端渲染

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

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

http://maxq.tigris.org/


编辑09-2013 UPDATE

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

Solution 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

If you don't want to add scripts to all pages look at option 2!

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

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

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

<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

Modify the intermediate frame to poll for changes

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

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

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

在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

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

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

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

9 回答

  • -2

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

    所以,你要么使用 postMessage (适用于所有现代浏览器),要么花5分钟从easyXDM调整resize iframe example .

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

  • 0

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

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

    最好,贝克

  • 0

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

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

    $(window).height();
    

    并将其用作iframe height属性 .

    好吧,结果是......

    我们永远不会有“页面”滚动,只有“iframe”滚动 . 当你导航时,无论谁是滚动,但重要的是只有1 .

    嗯,用户只需在导航时调整窗口大小就会出现问题 . 要解决这个问题,我使用:

    setInterval(getDocHeight, 1);
    

    您是否认为该解决方案会导致任何错误?它对我有用,在iFrame上我有php生成的动态对象 . 我害怕未来的错误......

  • 10

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

    只有第三个可以解决许多问题 . 例如 you can create responsive iFrame ;从里面关闭它或 you can communicate with it . 但要做到这一点,你需要iframe中的iFrame和"third party cookies"解决方法(可选) .

    我用例子创建了一篇关于它的文章:Event-driven cross-domain iFrame

  • 23

    你看过'object-fit' HTML5属性了吗?将视频/图像缩放到iframe,而不是缩放iframe(如果您抓取的中等大小的图像最终宽度为5,000px,则很好) . "fit"选项(其他为"cover"和"fill")使用信号排序方法来适应源,同时保留宽高比 . 对于通过HTML5-less进行查看,看起来好像有很多可用的polyfill . 这个很棒,但是Edge 's end has kept it incompatible with Microsoft'的新梦魇大约一年的错误,现在:https://github.com/anselmh/object-fit

    编辑:要解决跨域问题,您可以随时进行工作Chrome扩展内容脚本,因为它认为它是您坚持iframe的页面的一部分 .

  • 6

    HTTPS another link get height to iframe autoheight

    https://-a.com content:

    <!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 content:

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









    1









    2









    3









    4









    5









    6 </body> </html>

    Work Table:

    xcom http> ycom https WORK

    xcom https> ycom https WORK

    xcom http> ycom http WORK

    xcom https> ycom http WORK

    Test Work Screenshot

  • 0

    您是否希望找到iframe中包含的页面高度?我得到了一些javascript工作,它检查iframe内容的高度,然后将iframe的高度设置为内容的高度 .

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

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

  • -2

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

    这是在头脑中:(这是为PHP脚本编写的,对于html,更改'to'和\“to to ...

    <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”....对于同一页面上的多个“resizer”,复制相同的脚本但是更改iframe中的id和头部脚本中的名称,以及中提琴!你在同一页面上有多个缩放器...它工作得很好!

    有phun .

相关问题