Gibt es eine domänenübergreifende automatische Größenänderung für die Iframe-Höhe, die funktioniert?

109

Ich habe ein paar Lösungen ausprobiert, war aber nicht erfolgreich. Ich frage mich, ob es eine Lösung gibt, vorzugsweise mit einem einfach zu befolgenden Tutorial.

J82
quelle
2
Welche Lösungen haben Sie versucht, die nicht erfolgreich waren?
Yzmir Ramirez
1
Ich habe es versucht, aber es flippt in Webkit-Browsern aus, wie im Artikel angegeben: css-tricks.com/cross-domain-iframe-resizing Es gab ein anderes, aber ich kann mich nicht an die URL erinnern.
J82

Antworten:

68

Sie haben drei Alternativen:

1. Verwenden Sie iFrame-resizer

Dies ist eine einfache Bibliothek, mit der iFrames an ihren Inhalt angepasst werden können. Es verwendet die APIs PostMessage und MutationObserver mit Fallbacks für IE8-10. Es gibt auch Optionen für die Inhaltsseite, um anzufordern, dass der enthaltende iFrame eine bestimmte Größe hat, und kann den iFrame auch schließen, wenn Sie damit fertig sind.

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

2. Verwenden Sie Easy XDM (PostMessage + Flash-Kombination)

Easy XDM verwendet eine Reihe von Tricks, um die domänenübergreifende Kommunikation zwischen verschiedenen Fenstern in einer Reihe von Browsern zu ermöglichen. Es gibt Beispiele für die Verwendung für die Größenänderung von Iframes:

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 verwendet PostMessage in modernen Browsern und eine Flash-basierte Lösung als Ersatz für ältere Browser.

Siehe auch diesen Thread zu Stackoverflow (es gibt auch andere, dies ist eine häufig gestellte Frage). Auch Facebook scheint einen ähnlichen Ansatz zu verwenden .

3. Kommunizieren Sie über einen Server

Eine andere Möglichkeit wäre, die Iframe-Höhe an Ihren Server zu senden und dann von diesem Server über die übergeordnete Webseite mit JSONP abzufragen (oder wenn möglich eine lange Abfrage zu verwenden).

Janne Aukia
quelle
1
Wenn Sie für PostMessage bereits jQuery verwenden, sollten Sie sich auch das fantastische PostMessage-Plugin von Ben Alman ansehen: benalman.com/projects/jquery-postmessage-plugin
rinogo
8
iFrame-resizer benötigt Zugriff auf den Server, auf dem sich der Iframe-Inhalt befindet. Sie können es also nur für Domänen verwenden, die Sie steuern.
Hokascha
Guter Fang, @Hokascha. Das Projekt beansprucht Unterstützung für domänenübergreifende Iframes. Das Lesen der Dokumente zeigt jedoch, dass weiterhin Serverzugriff auf die eingebettete Domäne erforderlich ist.
StockB
1
Keine dieser "Alternativen" ist eine tatsächliche Lösung für dieses Problem. Der Fragesteller möchte die iFrame-Höhe von domänenübergreifenden iFrames von Websites festlegen, über die er keine Kontrolle hat. 1. Erfordert Serverzugriff. 2. Benötigt Software, die ich für schlecht halte. Easy XDM wurde wie vor 10 Jahren hergestellt. Die neueste Version von 2019 erfordert Flash . Flash ist zum Glück tot und niemand sollte sich darauf verlassen. 3. Erfordert Serverzugriff.
Redanimalwar
26

Ich habe die Lösung gefunden, um die Höhe des Iframes dynamisch basierend auf seinem Inhalt einzustellen. Dies funktioniert für den domänenübergreifenden Inhalt. Es sind einige Schritte zu befolgen, um dies zu erreichen.

  1. Angenommen, Sie haben iframe auf der Webseite "abc.com/page" hinzugefügt

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

  2. Als nächstes müssen Sie das Windows-Ereignis "message" unter der Webseite "abc.com/page" binden.

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);        
    }
});

Beim Laden des Iframes müssen Sie eine Nachricht mit der Nachricht "FrameHeight" an den Inhalt des Iframe-Fensters senden:

function setIframeHeight(ifrm) {
   var height = ifrm.contentWindow.postMessage("FrameHeight", "*");   
}
  1. Auf der Hauptseite, die hier unter iframe "xyz.pqr / contactpage" hinzugefügt wurde, müssen Sie das Windows "message" -Ereignis binden, bei dem alle Nachrichten vom übergeordneten Fenster von "abc.com/page" empfangen werden.
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 }, "*");       
    }
});
Sudhir
quelle
3
Funktioniert reibungslos. Tausend Dank!
Alex Leonov
einfach das ist die technischste Methode, die ich finden konnte, tolle Arbeit @sudhir, danke :)
java acm
14

Ich habe die iframe scrollWidth verglichen, bis sich ihre Größe geändert hat, während ich die IFrame-Höhe schrittweise eingestellt habe. Und es hat gut funktioniert für mich. Sie können das Inkrement nach Belieben einstellen.

   <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>
Troy Mitchel
quelle
4
Sie möchten wahrscheinlich die Anzahl der Schleifen begrenzen, andernfalls kann das 'while' zu einer Endlosschleife ausarten.
Kevin Seifert
1
Dies stürzt meine Seite ab.
DDDD
Gute einfache Lösung. In meinen Fällen wird das Größeninkrement jedoch durch die Bildschirmgröße begrenzt.
Zeta
1

Ich habe ein Skript, das mit seinem Inhalt in den Iframe eingefügt wird. Außerdem wird sichergestellt, dass iFrameResizer vorhanden ist (es wird als Skript eingefügt), und anschließend wird die Größenänderung vorgenommen.

Ich werde unten auf ein vereinfachtes Beispiel eingehen.

// /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/[email protected]/js/iframeResizer.contentWindow.min.js
        resizerScriptTag.src = 'https://unpkg.com/[email protected]/js/iframeResizer.min.js';
    } else {
        // Cool, the iFrameResizer exists so we can just load our iframe.
        loadIFrame();
    }    
}())

Dann kann der Iframe-Inhalt mithilfe des folgenden Skripts an eine beliebige Stelle innerhalb einer anderen Seite / Site eingefügt werden:

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

Der Iframe-Inhalt wird unten eingefügt, wo immer Sie das Skript-Tag platzieren.

Hoffe das ist hilfreich für jemanden. 👍

ctrlplusb
quelle
Schön, fügte ich hinzu <script ... data-src="http://google.com">und füllte den iframe src damit.
BananaAcid
1
... zu einem vollen nutzbaren Beispiel erweitert codesandbox.io/s/remote-embed-ifrm-qdb74
BananaAcid
@BananaAcid - Ihr Codesandbox-Link funktioniert nicht mehr
ctrlplusb
Vielen Dank für die Erwähnung, Links wurde: Codesandbox.io/s/remote-embed-ifrm-yz0xl . (Hinweis: Codesandbox "fälscht" auf mehreren Seiten und hängt möglicherweise. Das
erneute Laden
1

Hier ist meine einfache Lösung auf dieser Seite. http://lab.ohshiftlabs.com/iframesize/

So funktioniert es;

Geben Sie hier die Bildbeschreibung ein

Wenn Sie eine Seite in einer anderen Domain bearbeiten können, können Sie grundsätzlich eine andere Iframe-Seite platzieren, die zu Ihrem Server gehört und die Höhe von Cookies spart. Aktualisieren Sie die Höhe des Iframes mit einem Intervall zum Lesen von Cookies, wenn es aktualisiert wird. Das ist alles.

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

Bearbeiten: Dezember 2019

Die obige Lösung verwendet grundsätzlich einen anderen Iframe innerhalb eines Iframes. Der dritte Iframe gehört zur Domäne der obersten Seite, die Sie diese Seite mit einer Abfragezeichenfolge aufrufen, die den Größenwert in einem Cookie speichert. Die äußere Seite überprüft diese Abfrage mit einem gewissen Intervall. Aber es ist keine gute Lösung, deshalb sollten Sie dieser folgen:

In der oberen Seite:

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

Hier können Sie überprüfen m.origin, woher es kommt.

In der Rahmenseite:

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

Bitte vergessen Sie jedoch nicht, dass dies nicht so sicher ist. Um es sicher zu machen, aktualisieren Sie * den Wert (targetOrigin) mit Ihrem gewünschten Wert. Bitte folgen Sie der Dokumentation: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

Siniradam
quelle
1
Diese Links sind jetzt tot (404) und der Inhalt ist in der Antwort nicht zusammengefasst. :(
StockB
1
Links sind noch tot. 404
Arslan Ameer
0

Ich habe eine andere serverseitige Lösung für Webentwickler gefunden, die PHP verwendet, um die Größe eines Iframes zu erhalten.

Zunächst wird das Serverskript PHP für einen externen Aufruf über eine interne Funktion verwendet: (wie ein file_get_contentswith but curl und 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>

Sie müssen unter div ( iframe_reserve) das vom Funktionsaufruf generierte HTML mit einem einfachen anzeigenecho curl_get_file_contents("location url iframe","activation proxy")

Danach nimmt eine mit Javascript geladene Body-Event-Funktion die Höhe des Seiten-Iframes nur mit einer einfachen Steuerung des Inhalts div ( iframe_reserve) an.

Also habe ich die divHeight = document.getElementById("iframe_reserve").clientHeight;Höhe der externen Seite ermittelt, die wir nach dem Maskieren des div-Containers ( iframe_reserve) aufrufen werden . Danach laden wir den Iframe mit seiner guten Höhe, das ist alles.

Headmax
quelle
0

Ich bin auf dieses Problem gestoßen, als ich an etwas bei der Arbeit gearbeitet habe (mit React). Grundsätzlich haben wir einige externe HTML-Inhalte, die wir in unserer Dokumententabelle in der Datenbank speichern und dann unter bestimmten Umständen auf der Seite einfügen, wenn Sie sich im Dataset "Dokumente" befinden.

Also, da ninlines, von denen bis zu nexternen html enthalten könnte, brauchten wir ein System zu entwickeln , um automatisch die iframe jeden Inline - Größe ändern , sobald der Inhalt vollständig in jedem geladen. Nachdem ich ein bisschen mit den Rädern gedreht hatte, habe ich es so gemacht:

  1. Legen Sie messageim Index unserer React-App einen Ereignis-Listener fest, der nach einem bestimmten Schlüssel sucht, den wir vom Absender-Iframe festlegen.
  2. In der Komponente, die die Iframes tatsächlich rendert, füge ich nach dem Einfügen des externen HTML-Codes ein <script>Tag hinzu, das darauf wartet, dass die Iframes ausgelöst werden window.onload. Sobald dies ausgelöst wird, postMessagesenden wir eine Nachricht mit Informationen zur Iframe-ID, zur berechneten Höhe usw. an das übergeordnete Fenster.
  3. Wenn der Ursprung übereinstimmt und der Schlüssel im Index-Listener erfüllt ist, greifen Sie auf das DOM iddes Iframes zu, den wir im MessageEventObjekt übergeben
  4. Sobald wir das haben iframe, setzen Sie einfach die Höhe von dem Wert, der vom Iframe übergeben wird 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"
                )
            }
        }
    }}
/>
John Duncan
quelle