redimensionnement iframe inter-domaines
Comment redimensionner une iframe à partir d'un autre domaine
- Modifier
Faites défiler vers le bas pour quelques solutions.. ou lisez Comment ne pas le faire: D
Après de nombreuses heures de piratage de code - la conclusion est que tout ce qui se trouve dans 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 vous faire gagner du temps ne suivez même pas cette route utilisez simplement sendMessages pour cross domain communication. Il y a des plug-ins pour HTML
Ces derniers jours, j'ai essayé d'intégrer un iframe dans un site. C'est une solution à court terme tandis que l'autre côté développe et API(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 assez difficile de leur demander d'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 va mental de chrome et safari donc je ne peux pas l'utiliser.
Ouvrir dans 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 post sur la façon d'utiliser le scrollheight pour essayer de redimensionner le formulaire.. en théorie cela fonctionne bien mais je ne pouvais pas l'appliquer correctement en utilisant le hauteur de défilement des iframes..
document.body.scrollHeight
Qui utilise obvoisly la hauteur des corps (ne peut pas accéder à ces propriétés 100% est basé sur l'affichage des clients canvaz et non la hauteur du document x-domains)
J'ai essayé d'utiliser jquery pour obtenir la hauteur des iframes
$('#frameId').Height()
$('#frameId').clientHeight
$('#frameId').scrollHeight
Retourne des valeurs différentes dans chrome et ie-ou n'a tout simplement pas de sens du tout. Le problème est que tout à l'intérieur du cadre est refusé - même la barre de défilement...
Styles Calculés
Mais si je inspecter et élément dans chrome de l'iframe il bladdy me montre les dimensions des documents à l'intérieur de l'iframe (en utilisant jQuery x-domain pour obtenir iframe.hauteur - accès refusé) Il n'y a rien dans le CSS calculé
Maintenant, comment chrome calcule-t-il cela? (modifier-navigateur re-rend la page en utilisant sa construction dans le moteur de rendu à calcualte tous ces paramètres-mais ne sont pas attachés partout pour éviter la fraude inter-domaines.. si..)
HTML4
J'ai lu les spécifications de HTML4.x et il dit qu'il devrait y avoir des valeurs en lecture seule exposées via le document.élément mais son accès est refusé via jquery
Cadre Proxy
Je suis allé sur la route de proxy le site et le calcul 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/
Ré-afficher la page
Je ne suis pas allé aussi loin mais il y a des moteurs jscript qui vont regarder la source et re-rendre la page en fonction du fichier source . mais il faudrait pirater ces jscripts.. et ce n'est pas une situation idéale pour commercial entité... et quelques applets Java pur invole ou rendu côté serveur
Http://en.wikipedia.org/wiki/Server-side_JavaScript
Http://htmlunit.sourceforge.net/
Édition 09-2013 mise à jour
Tout cela peut être fait avec des sockets HTML5. Mais easyXDM est une excellente solution de repli pour les pages de plaintes non HTML5.
Solution 1 Très Bonne Solution!
Utiliser 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 suffit d'ajouter intermedate_frame html et easyXDM.js dans le même lieu. Comme un dossier parent-alors vous pouvez accéder à des répertoires relatifs ou un dossier Contenu juste 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 chaque page, vous avez besoin du redimensionnement pour se produire. Pas besoin d'inclure l'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 quelque part qui ressemble à:
<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 étrange et kind'of essaie de deviner ce qu'il devrait être .. et ne sera pas rétrécir vers le bas si vous en avez besoin.
OPTION 2
Modifier le cadre intermédiaire pour interroger les changements
Votre cadre intermédiaire devrait 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 chaeck si la taille a changé et seulement envoyer si les dimensions changent isntead de poster la messagerie toutes les 500ms. si vous implémentez cette vérification alors vous pouvez changer l'interrogation aussi bas que 50ms! amusez-vous
Travailler à travers les navigateurs et est rapide. Grandes fonctionnalités de débogage !!
Excellent Work to Sean Kinsey who made the script!!!
Solution 2 (Fonctionne mais pas beaucoup)
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 pas accès à l'autre domaine.. Continuez à chercher plus de hacks-parce que je ne pouvais pas 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 est-ce que quelques appels personnalisés que j'ai faits pour les appels de redimensionnement 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 et a un bon 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
Leur est maintenant une petite bibliothèque JS pour gérer le redimensionnement des iFrames inter-domaines, il faut toujours que l'iFrame ait un peu de JavaScript, cependant, ce n'est que 2.8 K (765 octets gzippés) DE JS natif qui n'a pas de dépendances et ne fait rien avant d'être appelé par la page parent. Cela signifie que c'est un bon invité sur les systèmes d'autres personnes.
Ce code utilise mutationObserver pour détecter les modifications DOM et recherche également les événements de redimensionnement, de sorte que l'iFrame reste dimensionné au contenu. Fonctionne dans IE8+.
9 réponses
La chose est-il n'y a pas d'autre moyen que d'utiliser la messagerie inter-domaines pour cela puisque vous devez obtenir la hauteur calculée d'un document dans un domaine, à un document dans un domaine différent.
Donc, soit vous le faites en utilisant postMessage
(fonctionne dans tous les navigateurs moder), soit vous passez 5 minutes à adapter l'exempleredimensionner iframe 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..
Semblable à ce que Sean a mentionné, vous pouvez utiliser postMessage. J'ai passé tellement de temps à essayer différentes façons de redimensionner iframe avec cross-domain mais pas de chance jusqu'à ce que je suis tombé sur ce grand 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 passez-la à la page parente (qui contient l'iframe). Remplacez element_id par votre id d'élément (html, body, whatever).
<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 parent, ajoutez ce code. Remplacez iframe_id par votre ID 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, la hauteur s'affiche dans le journal de la console. Cela vous aidera à déboguer, c'est pourquoi je l'ai laissé là.
MEILLEUR, Baker
Ayant regardé beaucoup de solution différente à cela, j'ai fini par écrire une petite bibliothèque simple pour prendre en compte un certain nombre de cas d'utilisation différents. Comme j'avais besoin d'une solution qui prenait en charge plusieurs iFrames générées par l'utilisateur sur une page de portail, le navigateur pris en charge redimensionne et pourrait faire face au chargement JavaScript de la page hôte après l'iFrame. J'ajoute également le support pour le dimensionnement à la largeur et une fonction de rappel et autorise le remplacement du corps.marge, comme vous voudrez probablement avoir cet ensemble à zéro.
Https://github.com/davidjbradshaw/iframe-resizer
Le code iframe est juste un petit JavaScript autonome, de sorte que c'est 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
);
}
});
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 iframe height.
Eh bien, le résultat est...
Nous n'aurons jamais le défilement "page", seulement le défilement" iframe". Lorsque vous naviguez, peu importe qui est le parchemin, mais l'important est qu'il n'y a que 1.
Eh bien, il y a le problème de l'utilisateur simplement redimensionner la fenêtre pendant qu'il navigue. Pour le résoudre, j' utilisation:
setInterval(getDocHeight, 1);
Pensez-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...
De nos jours, il n'y a que 4 solutions que je connais:
- postMessage. Certains navigateurs ne sont pas pris en charge bien sûr.
- fenêtre.emplacement.manipulations de hachage. Je pense que c'est solution #2 ici.
- easyXDM
- de la fenêtre.nom de Transport
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. Mais pour ce faire vous avez besoin d'iFrame Iframe et la solution de contournement" cookies tiers " (facultatif).
J'ai créé un article à ce sujet avec l'exemple: iframe cross-domain piloté par les événements
Avez-vous regardé dans les attributs HTML5 'object-fit'? Scales 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 être 5,000 px en largeur). L'option "fit" (d'autres sont "cover" et "fill") utilise une approche de type boîte aux lettres pour adapter la source tout en préservant les rapports d'aspect. Pour l'affichage par le HTML5-less là-bas, il semble qu'il y ait beaucoup de polyfills disponibles. Celui - ci est génial, mais un bug à la fin de Edge a gardé il est incompatible avec le nouveau cauchemar de Microsoft depuis environ un an, maintenant: https://github.com/anselmh/object-fit
EDIT: pour contourner les problèmes inter-domaines, vous pouvez toujours 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.
HTTPS un autre lien récupère la hauteur de iframe autoheight
Https://-a.com contenu:
<!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>
La Table De Travail:
XCOM http > ycom https travail
XCOM https > ycom https travail
XCOM http > YCOM http WORK
XCOM https > YCOM http WORK
Cherchez-vous à trouver la hauteur de la page contenue dans l'iframe? J'ai un peu de 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é.
Pour redimensionner un iframe, voici un script simple:
Cela va dans la tête: (ceci a été écrit pour un script php, pour html, changez le ' to "et le \ "to'...
<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>"
Extrémité de la tête
Cela va dans le corps (rappelez-vous, cela a été écrit pour un script php, pour html changer tout le ' to "et le \ "to'...)
<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 conseils ci-dessus. Comme il est défini pour les scripts php, vous pouvez faire beaucoup avec it...to en savoir plus, faire plus...
La clé de ceci est "sizeframe1".... pour plusieurs "resizers" sur la même page, copiez le même scénario, mais changer l'id en iframe et le nom du script dans la tête, et l'alto! vous avez plusieurs resizers sur le même page...it fonctionne très bien!
Avoir phun.