javascript - Ändra storlek på en iframe baserat på innehåll
Jag arbetar på en iGoogle-liknande applikation. Innehåll från andra applikationer (på andra domäner) visas med hjälp av iframes.
Hur ändrar jag storleken på iframes för att passa höjden på iframes innehåll?
Jag har försökt tyda den javascript som Google använder men den är oförståelig, och att söka på nätet har hittills varit fruktlöst.
Uppdatering: Observera att innehåll laddas från andra domäner, så policyn för samma ursprung gäller.
Svar #1
Vi hade den här typen av problem, men något omvänt jämfört med din situation - vi levererade det inbäddade innehållet till webbplatser på andra domäner, så samma ursprungsprincip var också ett problem. Efter många timmar av att söka på Google, hittade vi slutligen en (något..) fungerande lösning, som du kanske kan anpassa till dina behov.
Det finns ett sätt att kringgå policyn för samma ursprung, men det kräver ändringar både på det inbäddade innehållet och på inbäddningssidan, så om du inte har möjligheten att begära ändringar på båda sidor kommer denna metod tyvärr inte vara särskilt användbar för dig.
Det finns en webbläsarkonstighet som gör att vi kan kringgå samma ursprungsprincip - JavaScript kan kommunicera antingen med sidor på sin egen domän, eller med sidor som den har iframat, men aldrig sidor där den är iframad, t.ex. om du har:
www.foo.com/home.html, which iframes
|-> www.bar.net/framed.html, which iframes
|-> www.foo.com/helper.html
då kan home.html kommunicera med framed.html (iframe:ad) och helper.html (samma domän).
Communication options for each page:
+-------------------------+-----------+-------------+-------------+
| | home.html | framed.html | helper.html |
+-------------------------+-----------+-------------+-------------+
| www.foo.com/home.html | N/A | YES | YES |
| www.bar.net/framed.html | NO | N/A | YES |
| www.foo.com/helper.html | YES | YES | N/A |
+-------------------------+-----------+-------------+-------------+
framed.html kan skicka meddelanden till helper.html (iframed) men inte till home.html (child kan inte kommunicera över domän med parent).
Nyckeln här är att helper.html kan ta emot meddelanden från framed.html, och kan också kommunicera med home.html.
Så i princip, när framed.html laddas, räknar det ut sin egen höjd, berättar det för helper.html, som skickar meddelandet vidare till home.html, som då kan ändra storleken på iframe där framed.html ligger.
Det enklaste sättet vi fann för att skicka meddelanden från framed.html till helper.html var genom ett URL-argument. För att göra detta har framed.html en iframe med src='' specificerad. När dess onload utlöses, utvärderar den sin egen höjd och sätter src för iframe vid denna tidpunkt till helper.html?height=N
Det finns en förklaring här om hur Facebook hanterar det, vilket kan vara lite tydligare än min ovan!
Kod
I www.foo.com/home.html krävs följande javascript-kod (detta kan för övrigt laddas från en .js-fil på vilken domän som helst..):
<script>
// Resize iframe to full height
function resizeIframe(height)
{
// "+60" is a general rule of thumb to allow for differences in
// IE & and FF height reporting, can be adjusted as required..
document.getElementById('frame_name_here').height = parseInt(height)+60;
}
</script>
<iframe id='frame_name_here' src='http://www.bar.net/framed.html'></iframe>
I www.bar.net/framed.html:
<body onload="iframeResizePipe()">
<iframe id="helpframe" src='' height='0' width='0' frameborder='0'></iframe>
<script type="text/javascript">
function iframeResizePipe()
{
// What's the page height?
var height = document.body.scrollHeight;
// Going to 'pipe' the data to the parent through the helpframe..
var pipe = document.getElementById('helpframe');
// Cachebuster a precaution here to stop browser caching interfering
pipe.src = 'http://www.foo.com/helper.html?height='+height+'&cacheb='+Math.random();
}
</script>
Innehåll i www.foo.com/helper.html:
<html>
<!--
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content
-->
<body onload="parentIframeResize()">
<script>
// Tell the parent iframe what height the iframe needs to be
function parentIframeResize()
{
var height = getParam('height');
// This works as our parent's parent is on our domain..
parent.parent.resizeIframe(height);
}
// Helper function, parse param from request string
function getParam( name )
{
name = name.replace(/[\[]/,""[").replace(/[\]]/,""]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
</script>
</body>
</html>
Svar #2
Om du inte behöver hantera iframe-innehåll från en annan domän, prova denna kod, den kommer att lösa problemet helt och det är enkelt:
<script language="JavaScript">
<!--
function autoResize(id){
var newheight;
var newwidth;
if(document.getElementById){
newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
}
document.getElementById(id).height= (newheight) + "px";
document.getElementById(id).width= (newwidth) + "px";
}
//-->
</script>
<iframe src="usagelogs/default.aspx" width="100%" height="200px" id="iframe1" marginheight="0" frameborder="0" onLoad="autoResize('iframe1');"></iframe>
Svar #3
https://developer.mozilla.org/en/DOM/window.postMessage
window.postMessage()
window.postMessage är en metod för att säkert möjliggöra kommunikation mellan olika ursprung. Normalt får skript på olika sidor endast åtkomst till varandra om och endast om sidorna som körde dem befinner sig på platser med samma protokoll (vanligtvis båda http), portnummer (80 som standard för http) och värd (modulo document.domain som är satt av båda sidorna till samma värde). window.postMessage erbjuder en kontrollerad mekanism för att kringgå denna begränsning på ett sätt som är säkert när den används korrekt.
Sammanfattning
window.postMessage, när det anropas, orsakar att ett MessageEvent skickas till mål-fönstret när alla väntande skript som måste köras har slutförts (t.ex. återstående händelsehanterare om window.postMessage anropas från en händelsehanterare, tidigare inställda väntande timeouter, etc.). MessageEvent har typen message, en data-egenskap som sätts till strängvärdet av det första argumentet som tillhandahålls till window.postMessage, en origin-egenskap som motsvarar ursprunget till huvud-dokumentet i fönstret som anropar window.postMessage vid tidpunkten då window.postMessage anropades, och en source-egenskap som är fönstret från vilket window.postMessage anropas. (Andra standardegenskaper för händelser finns med sina förväntade värden.)
Biblioteket iFrame-Resizer använder postMessage för att hålla en iFrame anpassad till dess innehåll, tillsammans med MutationObserver för att upptäcka förändringar i innehållet och är inte beroende av jQuery.
https://github.com/davidjbradshaw/iframe-resizer
jQuery: Fördelar med skript över olika domäner
http://benalman.com/projects/jquery-postmessage-plugin/
Har demo av att ändra storlek på iframe-fönster...
http://benalman.com/code/projects/jquery-postmessage/examples/iframe/
Den här artikeln visar hur man tar bort beroendet av jQuery... Dessutom har den mycket användbar information och länkar till andra lösningar.
http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/
Grundläggande exempel...
http://onlineaspect.com/uploads/postmessage/parent.html
HTML 5 arbetsutkast om window.postMessage
http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
John Resig om meddelandeöverföring mellan fönster
http://ejohn.org/blog/cross-window-messaging/
