Búsqueda de sitios web

javascript - Redimensionar un iframe según el contenido


Estoy trabajando en una aplicación similar a iGoogle. El contenido de otras aplicaciones (en otros dominios) se muestra usando iframes.

¿Cómo puedo cambiar el tamaño de los iframes para que se ajusten a la altura del contenido de los iframes?

He intentado descifrar el JavaScript que Google usa, pero está ofuscado, y buscar en la web ha sido hasta ahora infructuoso.

Actualización: Tenga en cuenta que el contenido se carga desde otros dominios, por lo que se aplica la política de mismo origen.

Respuesta #1

Tuvimos este tipo de problema, pero ligeramente en sentido contrario a tu situación: estábamos proporcionando el contenido iframed a sitios en otros dominios, por lo que la política del mismo origen también era un problema. Después de muchas horas buscando en Google, finalmente encontramos una solución (algo...) viable, que podrías ser capaz de adaptar a tus necesidades.

Hay una manera de eludir la política del mismo origen, pero requiere cambios tanto en el contenido insertado en el iframe como en la página que lo enmarca, así que si no tienes la capacidad de solicitar cambios en ambos lados, me temo que este método no te será muy útil.

Hay una peculiaridad del navegador que nos permite eludir la política del mismo origen: javascript puede comunicarse ya sea con páginas en su propio dominio, o con páginas que haya incluido en un iframe, pero nunca con páginas en las que esté incluido en un iframe, por ejemplo, si tienes:

 www.foo.com/home.html, which iframes
 |-> www.bar.net/framed.html, which iframes
     |-> www.foo.com/helper.html

entonces home.html puede comunicarse con framed.html (en un iframe) y helper.html (mismo dominio).

 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 puede enviar mensajes a helper.html (incrustado en iframe) pero no a home.html (el hijo no puede comunicarse entre dominios con el padre).

La clave aquí es que helper.html puede recibir mensajes de framed.html, y también puede comunicarse con home.html.

Así que esencialmente, cuando framed.html se carga, calcula su propia altura, se lo comunica a helper.html, que pasa el mensaje a home.html, que luego puede redimensionar el iframe en el que framed.html se encuentra.

La forma más sencilla que encontramos para pasar mensajes de framed.html a helper.html fue a través de un argumento de URL. Para hacer esto, framed.html tiene un iframe con src='' especificado. Cuando se dispara su onload, evalúa su propia altura y establece el src del iframe en ese momento a helper.html?height=N

¡Aquí hay una explicación de cómo Facebook lo maneja, que puede ser un poco más clara que la mía arriba!


Código

En www.foo.com/home.html, se requiere el siguiente código javascript (esto se puede cargar desde un archivo .js en cualquier dominio, por cierto..):

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

En 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>

Contenido de 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>

Respuesta #2

Si no necesitas manejar contenido de iframe de un dominio diferente, prueba este código, resolverá el problema completamente y es simple:

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

Respuesta #3

https://developer.mozilla.org/en/DOM/window.postMessage

window.postMessage()

window.postMessage es un método para habilitar de manera segura la comunicación entre orígenes distintos. Normalmente, los scripts en diferentes páginas solo pueden acceder entre sí si y solo si las páginas que los ejecutan están en ubicaciones con el mismo protocolo (usualmente ambos http), número de puerto (80 siendo el predeterminado para http) y host (modulo document.domain establecido por ambas páginas al mismo valor). window.postMessage proporciona un mecanismo controlado para eludir esta restricción de manera segura cuando se utiliza correctamente.

Resumen

window.postMessage, cuando se llama, provoca que se despache un MessageEvent en la ventana objetivo cuando cualquier script pendiente que deba ejecutarse se complete (por ejemplo, controladores de eventos restantes si window.postMessage se llama desde un controlador de eventos, timeouts pendientes establecidos previamente, etc.). El MessageEvent tiene el tipo message, una propiedad data que se establece con el valor en cadena del primer argumento proporcionado a window.postMessage, una propiedad origin que corresponde al origen del documento principal en la ventana que llama a window.postMessage en el momento en que se llamó a window.postMessage, y una propiedad source que es la ventana desde la cual se llama a window.postMessage. (Otras propiedades estándar de eventos están presentes con sus valores esperados.)

La biblioteca iFrame-Resizer utiliza postMessage para mantener un iFrame ajustado a su contenido, junto con MutationObserver para detectar cambios en el contenido y no depende de jQuery.

https://github.com/davidjbradshaw/iframe-resizer

jQuery: La bondad de la programación entre dominios

http://benalman.com/projects/jquery-postmessage-plugin/

Tiene demostración de redimensionamiento de ventana iframe...

http://benalman.com/code/projects/jquery-postmessage/examples/iframe/

Este artículo muestra cómo eliminar la dependencia de jQuery... Además, tiene mucha información útil y enlaces a otras soluciones.

http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/

Ejemplo básico...

http://onlineaspect.com/uploads/postmessage/parent.html

Borrador de trabajo de HTML 5 sobre window.postMessage

http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages

John Resig sobre mensajería entre ventanas

http://ejohn.org/blog/cross-window-messaging/

Artículos relacionados