Comment redimensionner un iframe d'un autre domaine
-Éditer
Faites défiler vers le bas pour trouver des solutions ... ou lisez comment NE PAS faire cela: D
Après de nombreuses heures de piratage de code, la conclusion est que tout ce qui se trouve à l'intérieur de l'iframe n'est pas accessible, même les barres de défilement qui s'affichent sur mon domaine. J'ai essayé de nombreuses techniques en vain.
Pour gagner du temps, n'empruntez même pas cette voie, utilisez simplement sendMessages pour les communications interdomaines. Il y a des plug-ins pour HTML <5 que j'utilise - Allez en bas pour un bel exemple :)
Depuis quelques jours, j'ai essayé d'intégrer une iframe dans un site. C'est une solution à court terme pendant que l'autre côté développe et API (cela pourrait prendre des mois ...) Et parce que c'est une solution à court terme, nous voulons utiliser easyXDM - j'ai accès à l'autre domaine mais c'est déjà assez difficile de leur demander de ajouter l'en-tête p3p tel quel .....
3 iframes
La solution la plus proche que j'ai trouvée était les 3 iframes - mais cela devient mental de chrome et de safari, donc je ne peux pas l'utiliser.
ouvert en chrome
http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&height=1179
Mesurer les barres de défilement
J'ai trouvé un autre article sur la façon d'utiliser la hauteur de défilement pour essayer de redimensionner le formulaire .. en théorie, cela fonctionne bien mais je ne pouvais pas l'appliquer correctement en utilisant la hauteur de défilement des iframes.
document.body.scrollHeight
Cela utilise évidemment la hauteur du corps (impossible d'accéder à ces propriétés à 100% est basé sur l'affichage canvaz des clients et non sur la hauteur du document x-domaines)
J'ai essayé d'utiliser jquery pour obtenir la hauteur des iframes
$('#frameId').Height()
$('#frameId').clientHeight
$('#frameId').scrollHeight
renvoyer des valeurs différentes dans chrome et ie - ou tout simplement n'ont aucun sens. Le problème est que tout ce qui se trouve à l'intérieur du cadre est refusé - même la barre de défilement ...
Styles calculés
Mais si j'inspecte un élément dans le chrome de l'iframe, il me montre les dimensions des documents à l'intérieur de l'iframe (en utilisant jquery x-domain pour obtenir iframe.heigh - accès refusé) Il n'y a rien dans le CSS calculé
Maintenant, comment Chrome calcule-t-il cela? (edit-browser re-rend la page en utilisant son moteur de rendu intégré pour calculer tous ces paramètres - mais ne sont attachés nulle part pour éviter la fraude inter-domaines .. donc ..)
HTML4
J'ai lu la spécification de HTML4.x et il y est dit qu'il devrait y avoir des valeurs en lecture seule exposées via document.element mais son accès est refusé via jquery
Cadre proxy
J'ai emprunté la voie consistant à renvoyer le site par proxy et à calculer ce qui est OK ... jusqu'à ce qu'un utilisateur se connecte via l'iframe et que le proxy obtienne une page de connexion au lieu du contenu réel. Aussi pour certains appeler la page deux fois n'est pas acceptable
http://www.codeproject.com/KB/aspnet/asproxy.aspx
http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/
Rendre la page
Je ne suis pas allé jusque-là, mais il existe des moteurs jscript qui regardent la source et re-rendent la page en fonction du fichier source. mais cela exigerait le piratage de ces jscripts .. et ce n'est pas une situation idéale pour les entités commerciales ... et certaines applets java purs ou le rendu côté serveur
http://en.wikipedia.org/wiki/Server-side_JavaScript
http://htmlunit.sourceforge.net/ <-java pas jscript
MODIFIER LA MISE À JOUR 09-2013
Tout cela peut être fait avec des sockets HTML5. Mais easyXDM est une excellente solution de secours pour les pages de plainte non HTML5.
Solution 1 Très bonne solution!
Utilisation d'easyXDM
Sur votre serveur, vous configurez une page sous la forme de
<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>
et sur le domaine des appelants, il leur suffit d'ajouter le html intermiedate_frame et easyXDM.js au même endroit. Comme un dossier parent - alors vous pouvez accéder aux répertoires relatifs ou à un dossier contenu rien que pour vous.
OPTION 1
Si vous ne voulez pas ajouter de scripts à toutes les pages, regardez l'option 2!
Ensuite, ils peuvent simplement ajouter un simple jscript à la fin de chacune des pages dont vous avez besoin pour le redimensionnement. Pas besoin d'inclure easyxdm dans chacune de ces pages.
<script type="text/javascript">
window.onload = function(){ parent.socket.postMessage( (parseInt(document.body.clientHeight)) + "," + ( document.body.clientWidth ) ); };
</script>
J'ai modifié les paramètres qu'il envoie. Si vous voulez que la largeur fonctionne correctement, les pages de l'autre domaine doivent inclure la largeur de la page dans un style qui ressemble à quelque chose de similaire à:
<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>
Cela fonctionne très bien pour moi. Si la largeur n'est pas incluse, alors le cadre se comporte un peu bizarrement et kind'of essaie de deviner ce qu'il devrait être .. et ne rétrécira pas si vous en avez besoin.
OPTION 2
Modifier le cadre intermédiaire pour interroger les modifications
Votre cadre intermédiaire doit ressembler à ceci.
<!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>
L'intervalle pourrait être rendu plus efficace pour vérifier si la taille a changé et envoyer uniquement si les dimensions changent avant de publier un message toutes les 500 ms. Si vous implémentez cette vérification, vous pouvez modifier l'interrogation aussi bas que 50 ms! s'amuser
Travaillez sur tous les navigateurs et est rapide. Excellentes fonctionnalités de débogage !!
Excellent Work to Sean Kinsey who made the script!!!
Solution 2 (fonctionne mais pas super)
Donc, fondamentalement, si vous avez un accord mutuel avec l'autre domaine, vous pouvez ajouter une bibliothèque pour gérer sendmessage. Si vous n'avez aucun accès à l'autre domaine .. Continuez à chercher d'autres hacks - parce que je n'ai pas pu trouver ou justifier pleinement ceux que j'ai trouvés.
Donc, l'autre domaine les inclura dans la balise 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>
Dans le club.js, il y a juste quelques appels personnalisés que j'ai faits pour redimensionner les appels et contient ..
$(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 );
});
Et votre page fera tout le travail acharné et a un joli 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
Il s'agit maintenant d'une petite bibliothèque JS pour gérer le redimensionnement des iFrames inter-domaines, il faut toujours que l'iFrame contienne un peu de JavaScript, cependant, il ne s'agit que de 2,8k (765 octets gzippés) de JS natif qui n'a pas de dépendances et il ne fait rien tant qu'il n'est pas appelé par la page parent. Cela signifie que c'est un bon invité sur d'autres systèmes de personnes.
Ce code utilise mutationObserver pour détecter les changements DOM et recherche également les événements de redimensionnement, de sorte que l'iFrame reste dimensionné en fonction du contenu. Fonctionne dans IE8 +.
la source
Réponses:
Le fait est qu'il n'y a pas d'autre moyen que d'utiliser la messagerie inter-domaines pour cela, car vous devez obtenir la hauteur calculée d'un document dans un domaine à un document dans un domaine différent.
Donc, soit vous faites cela en utilisant
postMessage
(fonctionne dans tous les navigateurs modeurs), soit vous passez 5 minutes à adapter l' exemple d'iframe de redimensionnement d'easyXDM.L'autre partie a juste besoin de copier quelques fichiers sur son domaine et d'ajouter une seule ligne de code à son document.
la source
Comme ce que Sean a mentionné, vous pouvez utiliser postMessage. J'ai passé tellement de temps à essayer différentes façons de redimensionner l'iframe avec cross-domain, mais pas de chance avant de tomber sur ce super article de blog de David Walsh: http://davidwalsh.name/window-iframe
C'est une combinaison de mon code et de la solution de David. Ma solution est spécifiquement orientée vers le redimensionnement des iframes.
Dans la page enfant, recherchez la hauteur de la page et transmettez-la à la page parente (qui contient l'iframe). Remplacez element_id par votre identifiant d'élément (html, body, peu importe).
<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
Dans la fenêtre parente, ajoutez ce code. Remplacez iframe_id par votre identifiant 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>
Si vous ouvrez la console, vous verrez la hauteur imprimée dans le journal de la console. Cela vous aidera dans le débogage, c'est pourquoi je l'ai laissé là.
Meilleur, Baker
la source
Après avoir recherché différentes solutions à cela, j'ai fini par écrire une petite bibliothèque simple pour tenir compte d'un certain nombre de cas d'utilisation différents. Comme j'avais besoin d'une solution prenant en charge les iFrames générés par plusieurs utilisateurs sur une page de portail, le navigateur pris en charge les redimensionnements et pouvait faire face au chargement JavaScript de la page hôte après l'iFrame. J'ajoute également la prise en charge du dimensionnement à la largeur et une fonction de rappel et autorise le remplacement de body.margin, car vous voudrez probablement que ce paramètre soit défini sur zéro.
https://github.com/davidjbradshaw/iframe-resizer
Le code iframe est juste un petit JavaScript autonome, ce qui en fait un bon invité sur les pages d'autres personnes.
Le script est ensuite initialisé sur la page hôte avec les options disponibles suivantes.
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 ); } });
la source
Au lieu d'utiliser scroll = no sur l'iframe, je le change en "auto". Ensuite, j'obtiens la taille de la fenêtre réelle
$(window).height();
et utilisez-le comme attribut de hauteur iframe.
Eh bien, le résultat est ...
Nous n'aurons jamais le scroll "page", seulement le scroll "iframe". Lorsque vous naviguez, peu importe qui est le parchemin, mais l'important est qu'il n'y en ait qu'un.
Eh bien, il y a le problème de l'utilisateur qui redimensionne simplement la fenêtre pendant qu'il navigue. Pour résoudre cela, j'utilise:
setInterval(getDocHeight, 1);
Pensiez-vous que cette solution causera des bugs? Cela fonctionne pour moi, et sur l'iFrame j'ai eu un contect dynamique généré par php. J'ai peur des bugs futurs avec ça ...
la source
Aujourd'hui, je ne connais que 4 solutions:
Seul le troisième peut résoudre de nombreux problèmes. Par exemple, vous pouvez créer un iFrame réactif ; fermez-le de l'intérieur ou vous pouvez communiquer avec lui . Mais pour ce faire, vous avez besoin d'iFrame dans Iframe et de la solution de contournement «cookies tiers» (facultatif).
J'ai créé un article à ce sujet avec un exemple: iFrame inter-domaines piloté par les événements
la source
Avez-vous examiné les attributs HTML5 «ajustement à l'objet»? Met à l'échelle la vidéo / images à l'iframe, plutôt que de mettre à l'échelle l'iframe (bien si vous prenez une image de taille moyenne qui finit par avoir une largeur de 5000 pixels). L'option «fit» (les autres sont «cover» et «fill») utilise une approche de type boîte aux lettres pour adapter la source tout en préservant les proportions. Pour la visualisation par le HTML5-less là-bas, il semble qu'il y ait beaucoup de polyfills disponibles. Celui-ci est génial, mais un bogue du côté d'Edge l'a rendu incompatible avec le nouveau cauchemar de Microsoft pendant environ un an, maintenant: https://github.com/anselmh/object-fit
EDIT: Pour contourner les problèmes interdomaines, vous pouvez toujours simplement faire le travail dans un script de contenu d'extension Chrome, car il pense que cela fait partie de la page sur laquelle vous collez votre iframe.
la source
HTTPS un autre lien obtenir la hauteur de l'iframe autoheight
Contenu 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 contenu 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>
Table de travail:
xcom http> ycom https TRAVAIL
xcom https> ycom https TRAVAIL
xcom http> ycom http TRAVAIL
xcom https> ycom http TRAVAIL
la source
Cherchez-vous à trouver la hauteur de la page contenue dans l'iframe? J'ai fait fonctionner du javascript qui vérifie la hauteur du contenu iframe, puis définit la hauteur de l'iframe à la hauteur du contenu.
var Height = document.getElementById('iFrameId').contentWindow.document.body.scrollHeight; document.getElementById('iFrameId').height = Height;
Cependant, cela ne fonctionne que si la page que vous affichez dans l'iframe est sur le même domaine. Si ce n'est pas le cas, vous ne pouvez pas accéder aux informations requises. Par conséquent, l'erreur d'accès refusé.
la source
Pour redimensionner un iframe, voici un script simple:
cela va dans la tête: (cela a été écrit pour un script php, pour html, changez le 'en "et le \" en' ...
<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>"
fin de tête
cela va dans le corps (rappelez-vous, ceci a été écrit pour un script php, pour html changez tous les 'en' et les '' en '...)
<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: il y a quelques indices ci-dessus. Comme il est configuré pour les scripts php, vous pouvez en faire beaucoup ... pour en savoir plus, faire plus ...
la clé pour cela est "sizeframe1" .... pour plusieurs "resizers" sur la même page, copiez le même script mais changez l'id dans iframe et le nom dans le script dans la tête, et alto! vous avez plusieurs redimensionneurs sur la même page ... cela fonctionne très bien!
avoir phun.
la source