Esiste un ridimensionamento automatico dell'altezza dell'iframe interdominio che funzioni?


110

Ho provato alcune soluzioni ma non ho avuto successo. Mi chiedo se esista una soluzione preferibilmente con un tutorial facile da seguire.


2
Quali soluzioni hai provato che non hanno avuto successo?
Yzmir Ramirez

1
Ho provato questo ma va fuori di testa nei browser webkit come affermato nell'articolo: css-tricks.com/cross-domain-iframe-resizing Ce n'era un altro ma non ricordo l'URL.
J82


Risposte:


68

Hai tre alternative:

1. Usa iFrame-resizer

Questa è una semplice libreria per mantenere gli iFrame dimensionati in base al loro contenuto. Utilizza le API PostMessage e MutationObserver, con fall back per IE8-10. Ha anche opzioni per la pagina dei contenuti per richiedere che l'iFrame contenente sia di una certa dimensione e può anche chiudere l'iFrame quando hai finito.

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

2. Usa Easy XDM (PostMessage + Flash combo)

Easy XDM utilizza una raccolta di trucchi per abilitare la comunicazione interdominio tra diverse finestre in diversi browser, e ci sono esempi per utilizzarlo per il ridimensionamento iframe:

http://easyxdm.net/wp/2010/03/17/resize-iframe-based-on-content/

http://kinsey.no/blog/index.php/2010/02/19/resizing-iframes-using-easyxdm/

Easy XDM funziona utilizzando PostMessage sui browser moderni e una soluzione basata su Flash come riserva per i browser meno recenti.

Vedi anche questo thread su Stackoverflow (ce ne sono anche altri, questa è una domanda comune). Inoltre, Facebook sembrerebbe utilizzare un approccio simile .

3. Comunicare tramite un server

Un'altra opzione potrebbe essere quella di inviare l'altezza dell'iframe al tuo server e quindi eseguire il polling da quel server dalla pagina web principale con JSONP (o utilizzare un sondaggio lungo se possibile).


1
Per PostMessage, se stai già utilizzando jQuery, potresti anche voler esaminare il fantastico plug-in postMessage di
rinogo

8
iFrame-resizer ha bisogno dell'accesso al server che ospita il contenuto dell'iframe. Quindi puoi usarlo solo per i domini che controlli.
Hokascha

Buona cattura, @Hokascha. Il progetto rivendica il supporto per iframe interdominio, ma la lettura dei documenti rivela che richiede ancora l'accesso del server al dominio incorporato.
StockB

1
Nessuna di queste "alternative" rappresenta una soluzione effettiva a questo problema. Il richiedente desidera impostare l'altezza iFrame degli iFrame interdominio da siti Web su cui non ha il controllo. 1. Richiede l'accesso al server. 2. Richiede un software che considero scadente. Easy XDM è stato realizzato circa 10 anni fa. L'ultima versione, del 2019, richiede flash . Flash è, per fortuna, morto e nessuno dovrebbe fare affidamento su di esso. 3. Richiede l'accesso al server.
redanimalwar

26

Ho la soluzione per impostare l'altezza dell'iframe in modo dinamico in base al suo contenuto. Funziona per il contenuto interdominio. Ci sono alcuni passaggi da seguire per raggiungere questo obiettivo.

  1. Supponi di aver aggiunto iframe nella pagina web "abc.com/page"

    <div> <iframe id="IframeId" src="http://xyz.pqr/contactpage" style="width:100%;" onload="setIframeHeight(this)"></iframe> </div>

  2. Successivamente devi associare l'evento "messaggio" di Windows nella pagina web "abc.com/page"

window.addEventListener('message', function (event) {
//Here We have to check content of the message event  for safety purpose
//event data contains message sent from page added in iframe as shown in step 3
if (event.data.hasOwnProperty("FrameHeight")) {
        //Set height of the Iframe
        $("#IframeId").css("height", event.data.FrameHeight);        
    }
});

Al caricamento dell'iframe devi inviare un messaggio al contenuto della finestra dell'iframe con il messaggio "FrameHeight":

function setIframeHeight(ifrm) {
   var height = ifrm.contentWindow.postMessage("FrameHeight", "*");   
}
  1. Nella pagina principale aggiunta in iframe qui "xyz.pqr / contactpage" devi associare l'evento "message" di Windows in cui tutti i messaggi verranno ricevuti dalla finestra principale di "abc.com/page"
window.addEventListener('message', function (event) {

    // Need to check for safety as we are going to process only our messages
    // So Check whether event with data(which contains any object) contains our message here its "FrameHeight"
   if (event.data == "FrameHeight") {

        //event.source contains parent page window object 
        //which we are going to use to send message back to main page here "abc.com/page"

        //parentSourceWindow = event.source;

        //Calculate the maximum height of the page
        var body = document.body, html = document.documentElement;
        var height = Math.max(body.scrollHeight, body.offsetHeight,
            html.clientHeight, html.scrollHeight, html.offsetHeight);

       // Send height back to parent page "abc.com/page"
        event.source.postMessage({ "FrameHeight": height }, "*");       
    }
});

3
Funziona perfettamente. Grazie mille!
Alex Leonov

semplicemente questo è il metodo più tecnico che potrei trovare, ottimo lavoro @sudhir, grazie :)
java acm

14

Quello che ho fatto è stato confrontare l'iframe scrollWidth fino a quando non ha cambiato dimensione mentre ho impostato in modo incrementale l'altezza IFrame. E ha funzionato bene per me. È possibile regolare l'incremento in base alle proprie esigenze.

   <script type="text/javascript">
    function AdjustIFrame(id) {
        var frame = document.getElementById(id);
        var maxW = frame.scrollWidth;
        var minW = maxW;
        var FrameH = 100; //IFrame starting height
        frame.style.height = FrameH + "px"

        while (minW == maxW) {
            FrameH = FrameH + 100; //Increment
            frame.style.height = FrameH + "px";
            minW = frame.scrollWidth;
        }
    }

   </script>


<iframe id="RefFrame" onload="AdjustIFrame('RefFrame');" class="RefFrame"
    src="http://www.YourUrl.com"></iframe>

4
probabilmente vuoi aggiungere un limite al numero di loop, altrimenti il ​​"while" può degenerare in un loop infinito.
Kevin Seifert,

1
Questo sta bloccando la mia pagina.
DDDD

Buona soluzione semplice. Ma nel mio caso, l'incremento delle dimensioni è limitato dalle dimensioni dello schermo.
Zeta

1

Ho uno script che cade nell'iframe con il suo contenuto. Inoltre si assicura che iFrameResizer esista (lo inietta come uno script) e quindi esegue il ridimensionamento.

Farò un esempio semplificato di seguito.

// /js/embed-iframe-content.js

(function(){
    // Note the id, we need to set this correctly on the script tag responsible for
    // requesting this file.
    var me = document.getElementById('my-iframe-content-loader-script-tag');

    function loadIFrame() {
        var ifrm = document.createElement('iframe');
        ifrm.id = 'my-iframe-identifier';
        ifrm.setAttribute('src', 'http://www.google.com');
        ifrm.style.width = '100%';
        ifrm.style.border = 0;
        // we initially hide the iframe to avoid seeing the iframe resizing
        ifrm.style.opacity = 0;
        ifrm.onload = function () {
            // this will resize our iframe
            iFrameResize({ log: true }, '#my-iframe-identifier');
            // make our iframe visible
            ifrm.style.opacity = 1;
        };

        me.insertAdjacentElement('afterend', ifrm);
    }

    if (!window.iFrameResize) {
        // We first need to ensure we inject the js required to resize our iframe.

        var resizerScriptTag = document.createElement('script');
        resizerScriptTag.type = 'text/javascript';

        // IMPORTANT: insert the script tag before attaching the onload and setting the src.
        me.insertAdjacentElement('afterend', ifrm);

        // IMPORTANT: attach the onload before setting the src.
        resizerScriptTag.onload = loadIFrame;

        // This a CDN resource to get the iFrameResizer code.
        // NOTE: You must have the below "coupled" script hosted by the content that
        // is loaded within the iframe:
        // https://unpkg.com/iframe-resizer@3.5.14/js/iframeResizer.contentWindow.min.js
        resizerScriptTag.src = 'https://unpkg.com/iframe-resizer@3.5.14/js/iframeResizer.min.js';
    } else {
        // Cool, the iFrameResizer exists so we can just load our iframe.
        loadIFrame();
    }    
}())

Quindi il contenuto dell'iframe può essere iniettato ovunque all'interno di un'altra pagina / sito utilizzando lo script in questo modo:

<script
  id="my-iframe-content-loader-script-tag"
  type="text/javascript"
  src="/js/embed-iframe-content.js"
></script>

Il contenuto dell'iframe verrà inserito di seguito ovunque si inserisca il tag script.

Spero che questo sia utile a qualcuno. 👍


Bene, ho aggiunto <script ... data-src="http://google.com">e riempito l'iframe src con esso.
BananaAcid

Al momento della scrittura, la versione attuale èiframe-resizer@4.2.10
BananaAcid

1
... esteso a un esempio completo utilizzabile codesandbox.io/s/remote-embed-ifrm-qdb74
BananaAcid

@BananaAcid - il tuo link codesandbox non funziona più
ctrlplusb

grazie per averlo menzionato, i collegamenti sono diventati: codesandbox.io/s/remote-embed-ifrm-yz0xl . (nota: codesandbox "falsifica" utilizzando più pagine e potrebbe bloccarsi. Il ricaricamento potrebbe aiutare)
BananaAcid

1

Ecco la mia semplice soluzione in questa pagina. http://lab.ohshiftlabs.com/iframesize/

Ecco come funziona;

inserisci qui la descrizione dell'immagine

Fondamentalmente se sei in grado di modificare la pagina su un altro dominio puoi inserire un'altra pagina iframe che appartiene al tuo server che risparmia altezza ai cookie. Con un intervallo di lettura dei cookie quando viene aggiornato, aggiorna l'altezza dell'iframe. Questo è tutto.

Scarica; http://lab.ohshiftlabs.com/iframesize/iframesizepost.zip

Modifica: 2019 dicembre

La soluzione sopra utilizza fondamentalmente un altro iframe all'interno di un iframe. Il terzo iframe appartiene al dominio della pagina superiore, che chiami questa pagina con una stringa di query che salva il valore della dimensione in un cookie, la pagina esterna controlla questa query con un certo intervallo. Ma non è una buona soluzione, quindi dovresti seguire questa:

Nella pagina principale:

window.addEventListener("message", (m)=>{iframeResizingFunction(m)});

Qui puoi controllare m.originper vedere da dove viene.

Nella pagina frame:

window.parent.postMessage({ width: 640, height:480 }, "*")

Tuttavia, per favore non dimenticare che questo non è un modo così sicuro. Per renderlo sicuro, aggiorna * il valore (targetOrigin) con il valore desiderato. Segui la documentazione: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage


1
Questi collegamenti sono ora morti (404) e il contenuto non è riassunto nella risposta. :(
StockB

1
i collegamenti sono ancora morti. 404
Arslan Ameer

0

Ho trovato un'altra soluzione lato server per lo sviluppo web utilizzando PHP per ottenere le dimensioni di un iframe.

Il primo è usare lo script del server PHP per una chiamata esterna tramite la funzione interna: (come un file_get_contentswith but curl e dom).

function curl_get_file_contents($url,$proxyActivation=false) {
    global $proxy;
    $c = curl_init();
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7");
    curl_setopt($c, CURLOPT_REFERER, $url);
    curl_setopt($c, CURLOPT_URL, $url);
    curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
    if($proxyActivation) {
        curl_setopt($c, CURLOPT_PROXY, $proxy);
    }
    $contents = curl_exec($c);
    curl_close($c);
    $dom = new DOMDocument();
    $dom->preserveWhiteSpace = false;
    @$dom->loadHTML($contents);
    $form = $dom->getElementsByTagName("body")->item(0);
    if ($contents) //si on a du contenu
        return $dom->saveHTML();
    else
        return FALSE;
}
$url = "http://www.google.com"; //Exernal url test to iframe
<html>
    <head>
    <script type="text/javascript">

    </script>
    <style type="text/css">
    #iframe_reserve {
        width: 560px;
        height: 228px
    }
    </style>
    </head>

    <body>
        <div id="iframe_reserve"><?php echo curl_get_file_contents($url); ?></div>

        <iframe id="myiframe" src="http://www.google.com" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"  style="overflow:none; width:100%; display:none"></iframe>

        <script type="text/javascript">
            window.onload = function(){
            document.getElementById("iframe_reserve").style.display = "block";
            var divHeight = document.getElementById("iframe_reserve").clientHeight;
            document.getElementById("iframe_reserve").style.display = "none";
            document.getElementById("myiframe").style.display = "block";
            document.getElementById("myiframe").style.height = divHeight;
            alert(divHeight);
            };
        </script>
    </body>
</html>

È necessario visualizzare sotto div ( iframe_reserve) l'html generato dalla chiamata di funzione utilizzando un semplice fileecho curl_get_file_contents("location url iframe","activation proxy")

Dopo aver fatto ciò, una funzione di evento del corpo onload con javascript prende l'altezza dell'iframe della pagina solo con un semplice controllo del contenuto div ( iframe_reserve)

Quindi ho usato divHeight = document.getElementById("iframe_reserve").clientHeight;per ottenere l'altezza della pagina esterna che chiameremo dopo aver mascherato il contenitore div ( iframe_reserve). Dopodiché carichiamo l'iframe con la sua buona altezza, tutto qui.


0

Mi sono imbattuto in questo problema mentre lavoravo su qualcosa al lavoro (usando React). Fondamentalmente, abbiamo del contenuto html esterno che salviamo nella nostra tabella dei documenti nel database e poi inseriamo nella pagina in determinate circostanze quando sei nel set di dati Documenti.

Quindi, dati gli ninline, di cui fino a npotevano contenere html esterno, dovevamo ideare un sistema per ridimensionare automaticamente l'iframe di ogni inline una volta che il contenuto era completamente caricato in ciascuno. Dopo aver fatto girare le ruote per un po ', è così che ho finito per farlo:

  1. Imposta un messagelistener di eventi nell'indice della nostra app React che verifica la presenza di una chiave specifica che imposteremo dall'iframe del mittente.
  2. Nel componente che esegue effettivamente il rendering degli iframe, dopo aver inserito l'html esterno al suo interno, aggiungo un <script>tag che attenderà l'attivazione dell'iframe window.onload. Una volta che si attiva, usiamo postMessageper inviare un messaggio alla finestra principale con informazioni sull'id iframe, l'altezza calcolata, ecc.
  3. Se l'origine corrisponde e la chiave è soddisfatta nell'indice listener, prendi il DOM iddell'iframe che passiamo MessageEventnell'oggetto
  4. Una volta ottenuto iframe, imposta l'altezza dal valore passato dall'iframe postMessage.
// index
if (window.postMessage) {
    window.addEventListener("message", (messageEvent) => {
        if (
            messageEvent.data.origin &&
            messageEvent.data.origin === "company-name-iframe"
        ) {
            const iframe = document.getElementById(messageEvent.data.id)
            // this is the only way to ensure that the height of the iframe container matches its body height
            iframe.style.height = `${messageEvent.data.height}px`
            // by default, the iframe will not expand to fill the width of its parent
            iframe.style.width = "100%"
            // the iframe should take precedence over all pointer events of its immediate parent
            // (you can still click around the iframe to segue, for example, but all content of the iframe
            // will act like it has been directly inserted into the DOM)
            iframe.style.pointerEvents = "all"
            // by default, iframes have an ugly web-1.0 border
            iframe.style.border = "none"
        }
    })
}
// in component that renders n iframes
<iframe
    id={`${props.id}-iframe`}
    src={(() => {
        const html = [`data:text/html,${encodeURIComponent(props.thirdLineData)}`]
        if (window.parent.postMessage) {
            html.push(
                `
                <script>
                window.onload = function(event) {
                    window.parent.postMessage(
                        {
                            height: document.body.scrollHeight,
                            id: "${props.id}-iframe",
                            origin: "company-name-iframe",
                        },
                        "${window.location.origin}"
                    );
                };
                </script>
                `
            )
        }

        return html.join("\n")
    })()}
    onLoad={(event) => {
        // if the browser does not enforce a cross-origin policy,
        // then just access the height directly instead
        try {
            const { target } = event
            const contentDocument = (
                target.contentDocument ||
                // Earlier versions of IE or IE8+ where !DOCTYPE is not specified
                target.contentWindow.document
            )
            if (contentDocument) {
                target.style.height = `${contentDocument.body.scrollHeight}px`
            }
        } catch (error) {
            const expectedError = (
                `Blocked a frame with origin "${window.location.origin}" ` +
                `from accessing a cross-origin frame.`
            )
            if (error.message !== expectedError) {
                /* eslint-disable no-console */
                console.err(
                    `An error (${error.message}) ocurred while trying to check to see ` +
                    "if the inner iframe is accessible or not depending " +
                    "on the browser cross-origin policy"
                )
            }
        }
    }}
/>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.