jquery ruft beim Laden die Höhe des Iframe-Inhalts ab

84

Ich habe eine Hilfeseite, help.php, die ich in einen Iframe in main.php lade. Wie kann ich die Höhe dieser Seite ermitteln, nachdem sie in den Iframe geladen wurde?

Ich frage dies, weil ich die Höhe von iframe nicht auf 100% oder auto stylen kann. Deshalb denke ich, dass ich Javascript verwenden muss. Ich verwende jQuery

CSS:

body {
    margin: 0;
    padding: 0;
}
.container {
    width: 900px;
    height: 100%;
    margin: 0 auto;
    background: silver;
}
.help-div {
    display: none;
    width: 850px;
    height: 100%;
    position: absolute;
    top: 100px;
    background: orange;
}
#help-frame {
    width: 100%;
    height: auto;
    margin:0;
    padding:0;
}

JS:

$(document).ready(function () {
    $("a.open-help").click(function () {
        $(".help-div").show();
        return false;
    })
})

HTML:

<div class='container'>
    <!-- -->
    <div class='help-div'>
        <p>This is a div with an iframe loading the help page</p>
        <iframe id="help-frame" src="../help.php" width="100%" height="100%" frameborder="1"></iframe>
    </div>  <a class="open-help" href="#">open Help in iFrame</a>

    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
</div>
FFish
quelle
Kommt der Inhalt des iFrame von derselben Domain wie die Seite, auf der er sich befindet?
Andrew
Ja, es ist Andrew, ich möchte einen iFrame verwenden, weil ich Anker auf der
Hilfeseite verwende

Antworten:

102

ok ich habe endlich eine gute lösung gefunden:

$('iframe').load(function() {
    this.style.height =
    this.contentWindow.document.body.offsetHeight + 'px';
});

Da einige Browser (ältere Safari und Opera) den Onload-Vorgang vor dem Rendern von CSS als abgeschlossen melden, müssen Sie ein Micro-Timeout festlegen und den src des Iframes ausblenden und neu zuweisen.

$('iframe').load(function() {
    setTimeout(iResize, 50);
    // Safari and Opera need a kick-start.
    var iSource = document.getElementById('your-iframe-id').src;
    document.getElementById('your-iframe-id').src = '';
    document.getElementById('your-iframe-id').src = iSource;
});
function iResize() {
    document.getElementById('your-iframe-id').style.height = 
    document.getElementById('your-iframe-id').contentWindow.document.body.offsetHeight + 'px';
}
FFish
quelle
Diese Lösung funktioniert hervorragend, da die oben genannte Größe nur die Größe des Iframes-Inhalts im Container erhält, während die realGröße die Größe erhält
Rickyduck
2
Ich glaube, das Ladeereignis wird in derselben Ereignisschleife ausgelöst, sodass ein setTimout von 1 Millisekunde genauso gut funktioniert
George Mauer
hhmmm Jeder weiß, wie man die Höhe eines Iframes ermittelt, der zum Zeitpunkt des Ladens des übergeordneten Elements ausgeblendet ist. Diese Methode bringt 0.
JT ...
1
Möglicherweise möchten Sie die documentHöhe, nicht die bodyHöhe. Mit jQuery können Sie es greifen $(this.contentWindow.document).height().
vpiTriumph
Zu älter, dh iframe.contentDocument.body.offsetHeight funktioniert. stackoverflow.com/questions/2684693/…
user1087079
49

Die weniger komplizierte Antwort ist, um .contents()zum Iframe zu gelangen. Interessanterweise gibt es jedoch einen anderen Wert als den, den ich mit dem Code in meiner ursprünglichen Antwort erhalte, aufgrund der Polsterung am Körper, glaube ich.

$('iframe').contents().height() + 'is the height'

So habe ich es für die domänenübergreifende Kommunikation gemacht, daher befürchte ich, dass es möglicherweise unnötig kompliziert ist. Zuerst würde ich jQuery in das Dokument des iFrame einfügen. Dies verbraucht mehr Speicher, sollte jedoch die Ladezeit nicht verlängern, da das Skript nur einmal geladen werden muss.

Verwenden Sie die jQuery des iFrame, um die Höhe des Körpers Ihres Iframes so früh wie möglich zu messen (onDOMReady), und setzen Sie dann den URL-Hash auf diese Höhe. onloadFügen Sie im übergeordneten Dokument dem iFrame-Tag ein Ereignis hinzu, das die Position des Iframes überprüft und den gewünschten Wert extrahiert. Da onDOMReady immer vor dem Ladeereignis des Dokuments auftritt, können Sie ziemlich sicher sein, dass der Wert korrekt kommuniziert wird, ohne dass eine Race-Bedingung die Dinge kompliziert.

Mit anderen Worten:

... in Help.php:

var getDocumentHeight = function() {
    if (location.hash === '') { // EDIT: this should prevent the retriggering of onDOMReady
        location.hash = $('body').height(); 
        // at this point the document address will be something like help.php#1552
    }
};
$(getDocumentHeight);

... und im übergeordneten Dokument:

var getIFrameHeight = function() {
    var iFrame = $('iframe')[0]; // this will return the DOM element
    var strHash = iFrame.contentDocument.location.hash;
    alert(strHash); // will return something like '#1552'
};
$('iframe').bind('load', getIFrameHeight );
Andrew
quelle
Hallo Andrew bisher sehr gute Hilfe hier. content () funktioniert hervorragend, aber ich muss es noch mit einem Bandbreitendrossler testen. Möglicherweise können Sie die Eigenschaft innerHeight () verwenden. Ich habe ein Problem in FF (OSX) mit Ihrer Lösung, indem Sie die Höhe in den Hash setzen. FF scheint die Funktion getDocumentHeight () weiterhin in einer Endlosschleife zu laden? Safari ist in Ordnung ..
FFish
Interessant. Ich habe eine Prüfung hinzugefügt, die das Setzen des Hash verhindert, wenn dort bereits ein Wert vorhanden ist. Möglicherweise müssen Sie dies optimieren, wenn Sie Help.php mit einem Hash-Wert (z. B. <iframe src="../Help.php#introduction" />) laden
Andrew
Angenommen, Sie können den Höhenunterschied anpassen, müssen Sie den Hash wahrscheinlich nicht verwenden, um über den Iframe zu kommunizieren. Wenn Sie die Hash-Methode verwenden, sollte das sleep(5)Einfügen eines in Ihre Help.php auch eine gute Möglichkeit sein, um alle Rennbedingungen zu testen. Wenn der Iframe onLoadvorher irgendwie feuert onDOMReady, sollte er hier auftauchen.
Andrew
23

Ich habe festgestellt, dass Folgendes für Chrome, Firefox und IE11 funktioniert:

$('iframe').load(function () {
    $('iframe').height($('iframe').contents().height());
});

Wenn der Iframes-Inhalt geladen ist, wird das Ereignis ausgelöst und die IFrames-Höhe auf die des Inhalts festgelegt. Dies funktioniert nur für Seiten innerhalb derselben Domäne wie die des IFrames.

Jack Zach Tibbles
quelle
funktioniert ok aber für die Breite muss ich es so machen oder der Inhalt wird geschnitten $ ('iframe'). width ($ ('iframe'). content (). width () + 30);
Geomorillo
@AminGhaderi Funktioniert gut für mich in Firefox 40.0.3
Mixkat
@mixkat Ich lade eine Website in Iframe über diese Lösung und alle Lösungen in diesem Thema, aber für mich nicht funktionieren! Ich denke, diese Lösungen funktionieren für eine Seite und nicht, wenn wir eine vollständige Website in den Iframe laden. Mein Englisch ist sehr schlecht, ich hoffe du wirst es verstehen.
Amin Ghaderi
@AminGhaderi Wenn ich das richtig verstanden habe, erwarten Sie, dass dies für jede Seite Ihrer Site funktioniert, aber dies funktioniert natürlich nicht für alle Seiten, da es nur einmal ausgeführt wird, wenn Sie den Frame laden. Es funktioniert also gut für die erste Seite, aber wenn Sie möchten, dass es für längere Seiten funktioniert, müssen Sie es erneut tun, indem Sie den Frame erneut mit der neuen Seite laden oder die content.height an einem anderen Punkt in aufrufen Ihr Flow
Mixkat
9

Der Code, um dies ohne jQuery zu tun, ist heutzutage trivial:

const frame = document.querySelector('iframe')
function syncHeight() {
  this.style.height = `${this.contentWindow.document.body.offsetHeight}px`
}
frame.addEventListener('load', syncHeight)

So haken Sie die Veranstaltung aus:

frame.removeEventListener('load', syncHeight)
Kammerherr
quelle
3
Schön und einfach! Leider nicht für domänenübergreifende Iframes geeignet :(
TimoSolo
3
Ja, kein Glück da. Ich würde dafür die iframe-resizer-Bibliothek nutzen. Natürlich müssen Sie die Kontrolle über beide Domänen haben, damit es funktioniert.
Cchamberlain
6

Sie brauchen keine Abfrage im Iframe, um dies zu tun, aber ich benutze es, weil der Code so viel einfacher ist ...

Fügen Sie dies in das Dokument in Ihrem Iframe ein.

$(document).ready(function() {
  parent.set_size(this.body.offsetHeight + 5 + "px");  
});

oben fünf hinzugefügt, um die Bildlaufleiste in kleinen Fenstern zu entfernen, ist die Größe nie perfekt.

Und das in Ihrem übergeordneten Dokument.

function set_size(ht)
{
$("#iframeId").css('height',ht);
}
RkaneKnight
quelle
Dies funktioniert auch nicht, wenn Sie eine PDF-Datei im iframe anzeigen.
Jason Foglia
Entschuldigung, aber Ihr Beispiel "inside frame" basiert eindeutig auf jQuery.
T-Moty
4

Das ist die richtige Antwort, die für mich funktioniert hat

$(document).ready(function () {
        function resizeIframe() {
            if ($('iframe').contents().find('html').height() > 100) {
                $('iframe').height(($('iframe').contents().find('html').height()) + 'px')
            } else {
                setTimeout(function (e) {
                    resizeIframe();
                }, 50);
            }
        }
        resizeIframe();
    });
Javier Gordo
quelle
4

Ein einfacher Einzeiler beginnt mit einer Standard-Mindesthöhe und erhöht sich auf die Inhaltsgröße.

<iframe src="http://url.html" onload='javascript:(function(o){o.style.height=o.contentWindow.document.body.scrollHeight+"px";}(this));' style="height:200px;width:100%;border:none;overflow:hidden;"></iframe>

Pixelomo
quelle
1

Dies ist eine jQuery-freie Lösung, die mit SPA im Iframe zusammenarbeiten kann

document.getElementById('iframe-id').addEventListener('load', function () {
  let that = this;
  setTimeout(function () {
    that.style.height = that.contentWindow.document.body.offsetHeight + 'px';
  }, 2000) // if you're having SPA framework (angularjs for example) inside the iframe, some delay is needed for the content to populate
});
Neid
quelle
1

Dies ist meine ES6-freundliche No-JQuery-Einstellung

document.querySelector('iframe').addEventListener('load', function() {
    const iframeBody = this.contentWindow.document.body;
    const height = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight);
    this.style.height = `${height}px`;
});
César Rivera
quelle