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