跨域iframe调整大小 [英] cross-domain iframe resize

查看:212
本文介绍了跨域iframe调整大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

>如何从另一个域调整iframe的大小 >向下滚动以获取某些解决方案..或阅读如何不执行此操作:D



经过许多小时的代码黑客攻击后,得出的结论是iframe中的任何内容都不是甚至是在我的域上呈现的滚动条。我已经尝试了许多技术,但无济于事。为了节省时间,甚至不要为了跨域通信而使用sendMessages。
有插件用于HTML< 5,我使用 - 到底部的一个很好的例子:)




过去几天我一直在尝试整合一个iframe到一个网站。这是一个短期解决方案,而另一方开发和API(可能需要几个月......)
因为这是短期解决方案,我们想要使用easyXDM-我有权访问其他域,但它的难度足够要求他们添加p3p标头,因为它是.....



3个iframe



我找到的最接近的解决方案是3个iframe,但它的精髓在于Chrome和safari,因此我无法使用它。



在Chrome中打开



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



测量滚动条



我发现了另一篇关于如何使用scrollheight尝试调整窗体大小的帖子..理论上它运行良好,但我无法

  document.body.scrollHeight 

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

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

  $('#frameId')。Height()

$('#frameId')。clientHeight

$ ('#frameId')。scrollHeight

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



计算样式



但是,如果我检查iframe中的元素,它会显示iframe中的文档维度(使用jquery x-domain来获取iframe.heigh - 访问被拒绝)
计算的CSS中没有任何内容 b
$ b 现在如何计算铬? (编辑 - 浏览器使用其在渲染引擎中的内部版本重新渲染页面以计算所有这些设置 - 但没有附加到任何地方以防止跨域欺诈..所以..)



HTML4



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

代理框架 $ b

将代理网站返回并计算哪个是OK ..直到用户通过iframe登录并且代理获取登录页面而不是实际内容。也有人呼吁两次的网页是不可接受的



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



http://www.johnchapman.name/aspnet-proxy-page-跨域请求来自ajax-and-javascript /



重新呈现网页



我没有走这么远,但是有一些jscript引擎可以查看源代码并根据源文件重新渲染页面。但它需要黑客那些jscripts ..并且这不是商业实体的理想情况......
和一些invole纯java小程序或服务器端渲染



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



http://htmlunit.sourceforge.net/ < ; -java not jscript



http://maxq.tigris .org /






编辑09-2013
更新



所有这些都可以通过HTML5套接字完成。但easyXDM非常适合非HTML5投诉页面。



解决方案1 ​​<非常棒的解决方案!



使用easyXDM



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

 < html> 
< head>
< script src =scripts / easyXDM.jstype =text / javascript>< / script>
< script type =text / javascriptlanguage =javascript>

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

//将内联框架附加到
的元素ID container:embedded,
onMessage:function(message,origin){
var settings = message.split(,);
//在主页面上使用jquery
//$('iframe').height(settings[0]);
//$('iframe').width(settings[1]);

//不使用任何复杂页面的普通解决方案(默认)
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!
$ b 然后,他们可以将简单的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);
颜色:白色;
width:660px
}
a {
color:white;
visited:white;
}
< / style>

这对我很好。如果宽度没有包括在内,那么框架的表现会有点奇怪,并且会尝试猜测它应该是什么......并且如果您需要,它不会缩小。



< h2>选项2

修改中间框架以轮询更改

您中间框架应该看起来像这样。

 <!doctype html> 
< html>
< head>

< title> Frame< / title>
< script type =text / javascriptsrc =easyXDM.js>
< / script>
< script type =text / javascript>
var iframe;
var socket = new easyXDM.Socket({
//这是一个后备 - 在很多情况下不需要
swf:easyxdm.swf,
onReady:function() {
iframe = document.createElement(iframe);
iframe.frameBorder = 0;
document.body.appendChild(iframe);
iframe.src =主机FRAME;
iframe.onchange = messageBack();

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

//探测尺寸的child.frame。
函数messageBack(){
socket.postMessage(iframe.contentDocument.body.clientHeight +,+ iframe.contentDocument.body.clientWidth);
};

//每500毫秒轮询孩子的变化。
setInterval(messageBack(),500);

< / script>
< style type =text / css>
html,body {
overflow:hidden;
margin:0px;
padding:0px;
宽度:100%;
身高:100%;
}

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

< / body>
< / html>

如果尺寸发生变化,则间隔可以更有效,只有在尺寸变化时才发送每500ms发布一次消息。如果你执行这个检查,那么你可以改变轮询低至50ms!玩得开心






跨浏览器并且速度很快。很好的调试功能!!

 优秀的作品给Sean Kinsey制作剧本! 






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



因此,基本上如果你有与其他域的共同协议,那么你可以添加一个库来处理sendmessage。如果你没有访问其他域名的话。继续寻找更多的黑客 - 因为我找不到或完全证明我发现这些。



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

 < script src =scripts / jquery-1.5.2.min.js类型= 文本/ JavaScript的 >< /脚本> 
< script src =scripts / jquery.postmessage.min.jstype =text / javascript>< / script>
< script src =scripts / club.jstype =text / javascript>< / script>

在club.js中,我只是调整了一些自定义调用, p>

  $(document).ready(function(){
var parent_url = decodeURIComponent(document.location.hash.replace / ^#/,'')),link;
//向每个网址添加源网址哈希值,以便在帧内导航时授权回调。如果未点击任何链接,则会断开通信并且不会收到消息b $ b $('a [href]')。each(function(){
this.href = this.href + document.location.hash;
});
//
var h1 = document.body.scrollHeight;
var w1 = document.body.scrollWidth;
$ .postMessage({if_height:h1,if_width :w1},parent_url,parent);
});

您的网页将尽一切努力并且有一个不错的脚本...

  //这几乎就像request.querystring用于获取iframe数据
函数querySt(param,e){
gy = e.split(&);
for(i = 0; i ft = gy [i] .split(=);
if(ft [0] == param){
return ft [1];




$ b $(function(){
//跟踪iframe的尺寸
var if_height;
var if_width;
//以有意义的方式将父页面URL传递到iframe中(该URL可以是
//通过查询字符串传递或硬编码到子页面,这取决于你的需要)
src ='http://www.OTHERDOAMIN.co.uk/OTHERSTARTPAGE.htm'+'#'+ encodeURIComponent(document.location.href),
/ /将iframe添加到DOM中。
iframe = $('< iframesrc ='+ src +'width =100%height =100%scrolling =noframeborder = 0'>< \ / iframe>')。appendTo('#iframe');

//设置一个回调来处理调度的MessageEvent事件如果
/ / window.postMessage支持,传递的事件将有.data,.origin和
// .source属性。否则,这个只会有.data属性。
$ .receiveMessage(function(e){
//从传递的数据中获取高度
// 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){
//如果(!isNaN(w)&& w> 0&& w)高度已经改变,则更新iframe
iframe.height(if_height = h);
}
!== if_width){
//高度已经改变,更新iframe
iframe.width(if_width = w);
}
//仅用于调试 - 可以prepend(Recieved+ h +hX+ w +w ..);
//可选的原始网址(可选)忽略window.postMessage不受支持)。
//在这里,您只能将其他domain.com名称!这就像一个身份验证,以防止欺骗和xss攻击!
},'http://www.OTHERDOMAIN.co.uk');
});






方案3



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

这段代码使用了mutationObserver来检测DOM变化,并且寻找调整大小的事件,以便iFrame保持内容大小。适用于IE8 +。



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

解决方案

事情是 - 除了使用Cross-因为您需要从一个域中的文档到另一个域中的文档计算高度。



因此,要么使用 postMessage (适用于所有现代浏览器),或者花费5分钟时间来修改调整easyXDM的iframe示例



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


How do I resize an iframe from another domain

-Edit

Scroll down for some solutions.. or read on how NOT to do this :D

After many hours of code hacking- the conclusion is that anything inside the iframe is not accessible, even the scrollbars that render on my domain. I have tried many techniques to no avail.

To save you time don't even go down this route just use sendMessages for cross domain communications. There are plug ins for HTML < 5 that I use- Go to the bottom for a nice example :)


Past few days I have been trying to integrate an iframe into a site. This is a short term solution while the other side develops and API(could take months...) And because this is as short term solution we done want to use easyXDM- I have access to the other domain but its difficult enough asking them to add p3p header as it is.....

3 iframes

The closest solution I found was the 3 iframes- but it goes mental of chrome and safari so I cannot use that.

open in chrome

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

Measure the scrollbars

I found a another post on how to use the scrollheight to try and resize the form.. in theory it works well but I could not apply it properly using the iframes scroll height..

document.body.scrollHeight

That obvoisly uses the bodies height (cannot access these properties 100% is based on the clients display canvaz and not the x-domains document height)

I tried using jquery to get the iframes height

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight

return values different in chrome and ie - or just don't make sense at all. The problem is that everything inside the frame is denied- even the scrollbar...

Computed Styles

But if I inspect and element in chrome of the iframe it bladdy shows me the documents dimensions inside the iframe (using jquery x-domain to get iframe.heigh - access denied) There is nothing in the computed CSS

Now how does chrome calculate that? (edit- browser re-renders the page using its build in rendering engine to calcualte all these settings - but are not attached anywhere to prevent cross-domain fraud.. so..)

HTML4

I read specification of HTML4.x and it says there that there should be read-only values exposed via document.element but it's access denied via jquery

Proxy Frame

I went down the route of proxying the site back and calculating which is OK.. until a user logs in through the iframe and the proxy gets a login page instead of the actual content. Also to some calling the page twice is not acceptable

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

I did not go this far but there are jscript engines out there that will look at the source and re-render the page based on the source file . but it would require hacking those jscripts.. and thats not an ideal situation for commercial entities... and some invole pure java applets or server side rendering

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

http://htmlunit.sourceforge.net/ <-java not jscript

http://maxq.tigris.org/


EDIT 09-2013 UPDATE

All this can do done with HTML5 sockets. But easyXDM is great fallback for non HTML5 complaint pages.

Solution 1 Very Great Solution!

Using easyXDM

On your server you set up a page in the form of

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

and on the callers domain they just need to add the intermiedate_frame html and easyXDM.js in the same place. Like a parent folder - then you can access relative directories or a contained folder just for you.

OPTION 1

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

Then they can just add a simple jscript to the end of each the pages you need the resize to occur. No need to include the easyxdm in each of these pages.

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

I have modified the parameters it sends. If you want the width to work properly then the pages on the otherdomain need to include the width of the page in a style somwhere that look something similar to:

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

This works great for me. If the width is not included then the frame behaves a bit strange and kind'of tries to guess what it should be .. and will not shrink down if you need it to.

OPTION 2

Modify the intermediate frame to poll for changes

Your intermediate frame should look something like this..

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

The interval could be made more efficient to chaeck if size has change and only send if the dimensions changes isntead of posting messaging every 500ms. If you implement this check then you can change the polling as low as 50ms! have fun


Work across browsers and is fast. Great debugging features !!

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


Solution 2 (Works but not great)

So basically if you have a mutual agreement with the other domain then you can add a library to handle sendmessage. If you do not have any access the the other domain.. Keep on looking for more hacks- because I could not find or fully justify these I found.

So the other domain will include these in there Head tag

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

In the club.js is just some custom calls i made for resize calls and contains..

 $(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 );
  });

And your page will do all the hard work and has a nice script...

  //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');
     });


OPTION 3

Their is now a small JS library for managing resizing cross-domain iFrames, it still requires the iFrame to have a bit of JavaScript in it, however, this is just 2.8k (765 bytes Gzipped) of native JS that does not have any dependancies and it doesn't do anything until called by the parent page. This means it's a nice guest on other people systems.

This code uses mutationObserver to detect DOM changes and also looks out for resize events, so that the iFrame remains sized to the content. Works in IE8+.

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

解决方案

The thing is - there is no other way than using Cross-Domain Messaging for this since you need to get the computed height from a document in one domain, to a document in a different domain.

So, either you do this using postMessage (works in all moder browsers), or you spend 5 minutes adapting the resize iframe example from easyXDM.

The other party really just needs to copy a few files onto their domain, and add a single line of code to their document..

这篇关于跨域iframe调整大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆