Jak zmienić rozmiar elementu iframe z innej domeny
-Edytować
Przewiń w dół, aby znaleźć rozwiązania ... lub przeczytaj, jak tego NIE robić: D
Po wielu godzinach hakowania kodu - wniosek jest taki, że nic wewnątrz iframe nie jest dostępne, nawet paski przewijania, które renderują się w mojej domenie. Próbowałem wielu technik bezskutecznie.
Aby zaoszczędzić czas, nie idź nawet tą drogą, po prostu używaj sendMessages do komunikacji między domenami. Są wtyczki do HTML <5, których używam - Idź na dół po fajny przykład :)
Od kilku dni próbuję zintegrować ramkę iframe ze stroną. Jest to rozwiązanie krótkoterminowe, podczas gdy druga strona rozwija i API (może zająć miesiące ...) A ponieważ jest to rozwiązanie krótkoterminowe, które zrobiliśmy, chcemy używać easyXDM - mam dostęp do innej domeny, ale trudno jest poprosić ich o dodaj nagłówek p3p taki jaki jest .....
3 ramki iframe
Najbliższym rozwiązaniem, które znalazłem, były 3 ramki iframe - ale jest to myślenie o chrome i safari, więc nie mogę tego użyć.
otwórz w chromie
http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&height=1179
Zmierz paski przewijania
Znalazłem kolejny post o tym, jak użyć wysokości przewijania, aby spróbować zmienić rozmiar formularza .. w teorii działa dobrze, ale nie mogłem go poprawnie zastosować przy użyciu wysokości przewijania elementów iframe.
document.body.scrollHeight
To oczywiście używa wysokości ciała (nie można uzyskać dostępu do tych właściwości w 100% jest oparte na wyświetlaniu przez klientów canvaz, a nie wysokości dokumentu x-domains)
Próbowałem użyć jquery, aby uzyskać wysokość ramek iframe
$('#frameId').Height()
$('#frameId').clientHeight
$('#frameId').scrollHeight
zwracają różne wartości w chrome i ie - lub po prostu nie mają sensu. Problem w tym, że wszystko w ramce jest odrzucane - nawet pasek przewijania ...
Style obliczone
Ale jeśli sprawdzę i element w chrome elementu iframe, bladdy pokazuje mi wymiary dokumentów wewnątrz iframe (używając jquery x-domain, aby uzyskać iframe.heigh - odmowa dostępu) Nie ma nic w obliczonym CSS
Jak Chrome to oblicza? (edycja - przeglądarka ponownie renderuje stronę przy użyciu wbudowanego silnika renderującego, aby obliczyć wszystkie te ustawienia - ale nie są nigdzie dołączane, aby zapobiec oszustwom międzydomenowym ... więc ...)
HTML4
Przeczytałem specyfikację HTML4.x i jest tam napisane, że powinny istnieć wartości tylko do odczytu ujawniane przez document.element, ale dostęp do niego jest zabroniony przez jquery
Ramka proxy
Zszedłem na ścieżce proxy z powrotem do witryny i obliczania, co jest w porządku, dopóki użytkownik nie zaloguje się przez iframe, a proxy nie otrzyma strony logowania zamiast rzeczywistej zawartości. Niedopuszczalne jest również dwukrotne wywołanie strony
http://www.codeproject.com/KB/aspnet/asproxy.aspx
http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/
Ponownie wyrenderuj stronę
Nie posunąłem się tak daleko, ale istnieją silniki jscript, które sprawdzą źródło i ponownie wyrenderują stronę w oparciu o plik źródłowy. ale wymagałoby to zhakowania tych skryptów jscriptu ... i to nie jest idealna sytuacja dla podmiotów komercyjnych ... i niektórych niezrozumiałych apletów Java lub renderowania po stronie serwera
http://en.wikipedia.org/wiki/Server-side_JavaScript
http://htmlunit.sourceforge.net/ <-java not jscript
EDYTUJ AKTUALIZACJĘ 09-2013
Wszystko to można zrobić za pomocą gniazd HTML5. Ale easyXDM jest świetnym rozwiązaniem zastępczym dla stron skarg innych niż HTML5.
Rozwiązanie 1 Bardzo dobre rozwiązanie!
Korzystanie z easyXDM
Na swoim serwerze zakładasz stronę w postaci
<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>
a na domenie dzwoniącej wystarczy dodać intermiedate_frame html i easyXDM.js w tym samym miejscu. Podobnie jak folder nadrzędny - możesz wtedy uzyskać dostęp do katalogów względnych lub folderu zawartego tylko dla Ciebie.
OPCJA 1
Jeśli nie chcesz dodawać skryptów do wszystkich stron, spójrz na opcję 2!
Następnie mogą po prostu dodać prosty skrypt jscript na końcu każdej strony, na której chcesz zmienić rozmiar. Nie ma potrzeby dołączania easyxdm na każdej z tych stron.
<script type="text/javascript">
window.onload = function(){ parent.socket.postMessage( (parseInt(document.body.clientHeight)) + "," + ( document.body.clientWidth ) ); };
</script>
Zmodyfikowałem parametry, które wysyła. Jeśli chcesz, aby szerokość działała poprawnie, strony w innej domenie muszą zawierać szerokość strony w stylu, który wygląda podobnie do:
<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>
To działa świetnie dla mnie. Jeśli szerokość nie jest podana, ramka zachowuje się trochę dziwnie i jakby próbuje odgadnąć, jaka powinna być ... i nie zmniejszy się, jeśli tego potrzebujesz.
OPCJA 2
Zmodyfikuj ramkę pośrednią, aby odpytywać o zmiany
Twoja ramka pośrednia powinna wyglądać mniej więcej tak.
<!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>
Interwał mógłby być bardziej efektywny, aby zmierzyć rozmiar, jeśli rozmiar się zmienił i wysłać tylko wtedy, gdy zmiany wymiarów nie są zakończone wysyłaniem wiadomości co 500 ms. Jeśli zastosujesz tę kontrolę, możesz zmienić odpytywanie już od 50 ms! baw się dobrze
Działa w różnych przeglądarkach i jest szybki. Świetne funkcje debugowania !!
Excellent Work to Sean Kinsey who made the script!!!
Rozwiązanie 2 (działa, ale nie jest świetne)
Więc zasadniczo, jeśli masz wzajemną umowę z inną domeną, możesz dodać bibliotekę do obsługi sendmessage. Jeśli nie masz dostępu do innej domeny ... Szukaj dalej hacków - ponieważ nie mogłem znaleźć ani w pełni uzasadnić tych, które znalazłem.
Więc druga domena będzie zawierała je w tagu Head
<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>
W pliku club.js jest tylko kilka niestandardowych wywołań, które wykonałem w celu zmiany rozmiaru i zawiera ...
$(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 );
});
Twoja strona wykona całą ciężką pracę i ma ładny skrypt ...
//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');
});
OPCJA 3
Jest to teraz mała biblioteka JS do zarządzania zmianą rozmiaru międzydomenowych ramek iFrame, nadal wymaga, aby iFrame zawierało trochę JavaScript, jednak to tylko 2,8k (765 bajtów spakowanych Gzipem) natywnego JS, który nie ma żadnych zależności i nic nie robi, dopóki nie zostanie wywołane przez stronę nadrzędną. Oznacza to, że jest miłym gościem w systemach innych ludzi.
Ten kod wykorzystuje mutationObserver do wykrywania zmian DOM, a także wyszukuje zdarzenia zmiany rozmiaru, dzięki czemu element iFrame pozostaje dopasowany do zawartości. Działa w IE8 +.
źródło
Odpowiedzi:
Rzecz w tym, że nie ma innego sposobu niż użycie do tego celu przesyłania wiadomości międzydomenowych, ponieważ musisz pobrać obliczoną wysokość z dokumentu w jednej domenie do dokumentu w innej domenie.
Więc albo robisz to za pomocą
postMessage
(działa we wszystkich nowoczesnych przeglądarkach), albo spędzasz 5 minut na dostosowywaniu przykładu zmiany rozmiaru elementu iframe z easyXDM.Druga strona naprawdę musi tylko skopiować kilka plików do swojej domeny i dodać jedną linię kodu do swojego dokumentu.
źródło
Podobnie jak wspomniał Sean, możesz użyć postMessage. Spędziłem tak dużo czasu na próbowaniu różnych sposobów zmiany rozmiaru iframe przy użyciu wielu domen, ale bez powodzenia, dopóki nie natknąłem się na ten wspaniały post na blogu Davida Walsha: http://davidwalsh.name/window-iframe
To jest połączenie mojego kodu i rozwiązania Davida. Moje rozwiązanie jest ukierunkowane specjalnie na zmianę rozmiaru ramek iframe.
Na stronie podrzędnej znajdź wysokość strony i przekaż ją do strony nadrzędnej (zawierającej element iframe). Zastąp element_id swoim identyfikatorem elementu (html, body, cokolwiek).
<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
W oknie nadrzędnym dodaj ten kod. Zastąp iframe_id swoim identyfikatorem iframe:
<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>
Jeśli otworzysz konsolę, zobaczysz wysokość drukowaną w dzienniku konsoli. Pomoże ci to w debugowaniu, dlatego go tam zostawiłem.
Najlepsze, Baker
źródło
Rozejrzawszy się za wieloma różnymi rozwiązaniami tego problemu, napisałem prostą, małą bibliotekę, aby uwzględnić szereg różnych przypadków użycia. Ponieważ potrzebowałem rozwiązania obsługującego wiele ramek iFrame generowanych przez użytkowników na stronie portalu, obsługiwana przeglądarka zmienia rozmiar i mogłaby poradzić sobie z ładowaniem JavaScript strony hosta po elemencie iFrame. Dodam również obsługę rozmiaru do szerokości i funkcję zwrotną oraz zezwalam na nadpisanie body.margin, ponieważ prawdopodobnie będziesz chciał ustawić to na zero.
https://github.com/davidjbradshaw/iframe-resizer
Kod iframe to po prostu mały samodzielny kod JavaScript, dzięki czemu jest dobrym gościem na stronach innych osób.
Skrypt jest następnie inicjowany na stronie hosta z następującymi dostępnymi opcjami.
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 ); } });
źródło
Zamiast używać scroll = no w ramce iframe, zmieniam ją na „auto”. Następnie otrzymuję rozmiar rzeczywistego okna
$(window).height();
i użyj tego jako atrybutu wysokości elementu iframe.
Cóż, wynik jest ...
Nigdy nie będziemy mieć przewijania „strony”, tylko przewijanie „iframe”. Kiedy nawigujesz, nie ma znaczenia, kto jest zwojem, ale ważne jest, że jest tylko 1.
Cóż, problem polega na tym, że użytkownik po prostu zmienia rozmiar okna podczas nawigacji. Aby to rozwiązać, używam:
setInterval(getDocHeight, 1);
Czy myślałeś, że to rozwiązanie spowoduje jakieś błędy? To działa dla mnie, a na iFrame miałem dynamiczny kontekt wygenerowany przez php. Boję się przyszłych błędów z tym ...
źródło
Obecnie znam tylko 4 rozwiązania:
Dopiero trzecia może rozwiązać wiele problemów. Na przykład możesz utworzyć responsywną ramkę iFrame ; zamknij go od wewnątrz lub możesz się z nim komunikować . Ale aby to zrobić, potrzebujesz elementu iFrame w iframe i obejścia „plików cookie innych firm” (opcjonalnie).
Stworzyłem o tym artykuł z przykładem: iFrame międzydomenowa sterowana zdarzeniami
źródło
Czy przyjrzałeś się atrybutom HTML5 „dopasowanym do obiektu”? Skaluje wideo / obrazy do elementu iframe, zamiast skalować element iframe (fajnie, jeśli złapiesz obraz o średniej wielkości, który kończy się na 5000 pikseli szerokości). Opcja „Dopasuj” (inne to „okładka” i „wypełnienie”) wykorzystuje podejście typu „letterbox”, aby dopasować źródło przy zachowaniu współczynników proporcji. Wygląda na to, że do oglądania przez program HTML5 bez HTML5 jest dostępnych mnóstwo polyfillów. Ten jest świetny, ale błąd na końcu Edge sprawił, że był niezgodny z New Nightmare Microsoftu przez około rok, teraz: https://github.com/anselmh/object-fit
EDYCJA: Aby obejść problemy między domenami, zawsze możesz po prostu wykonać pracę w skrypcie zawartości rozszerzenia Chrome, ponieważ uważa, że jest to część strony, na której trzymasz element iframe.
źródło
HTTPS inny link uzyskuje wysokość do autoheight elementu iframe
Treść 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 zawartość 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>
Stół do pracy:
xcom http> ycom https WORK
xcom https> ycom https WORK
xcom http> ycom http WORK
xcom https> ycom http WORK
źródło
Czy chcesz znaleźć wysokość strony zawartej w elemencie iframe? Mam działający javascript, który sprawdza wysokość zawartości iframe, a następnie ustawia wysokość iframe na wysokość treści.
var Height = document.getElementById('iFrameId').contentWindow.document.body.scrollHeight; document.getElementById('iFrameId').height = Height;
Działa to jednak tylko wtedy, gdy strona, którą wyświetlasz w elemencie iframe, znajduje się w tej samej domenie. Jeśli tak nie jest, nie możesz uzyskać dostępu do wymaganych informacji. W związku z tym błąd odmowy dostępu.
źródło
Aby zmienić rozmiar elementu iframe, oto prosty skrypt:
to idzie do głowy: (to zostało napisane dla skryptu php, dla html, zmień 'na "i \" na' ...
<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>"
koniec głowy
to idzie do treści (pamiętaj, że zostało to napisane dla skryptu php, dla html zmień wszystkie 'na "i \" na' ...)
<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>
bonus: powyżej jest kilka wskazówek. Ponieważ jest ustawiony na skrypty php, możesz z nim wiele zrobić ... aby dowiedzieć się więcej, zrób więcej ...
kluczem do tego jest "sizeframe1" .... dla wielu "resizerów" na tej samej stronie, skopiuj ten sam skrypt, ale zmień id w iframe i nazwę w skrypcie w head i viola! masz wiele zmian rozmiaru na tej samej stronie ... działa bardzo dobrze!
mam phun.
źródło