jquery pobiera wysokość zawartości iframe po załadowaniu

84

Mam stronę pomocy, help.php, którą ładuję wewnątrz elementu iframe w main.php. Jak mogę uzyskać wysokość tej strony po załadowaniu jej do iframe?

Pytam o to, ponieważ nie mogę ustawić wysokości elementu iframe na 100% ani automatycznie. Dlatego myślę, że muszę używać javascript .. Używam 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
źródło
Czy zawartość elementu iFrame pochodzi z tej samej domeny, co strona, na której się znajduje?
Andrew
tak, to andrew, chcę użyć iFrame, ponieważ używam kotwic na stronie pomocy
FFish

Odpowiedzi:

102

ok w końcu znalazłem dobre rozwiązanie:

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

Ponieważ niektóre przeglądarki (starsze Safari i Opera) raportują, że ładowanie zakończyło się przed renderowaniem CSS, musisz ustawić mikro limit czasu, wyczyścić i ponownie przypisać src elementu iframe.

$('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
źródło
to rozwiązanie działa świetnie, ponieważ powyższe po prostu pobiera rozmiar z kokentu iframe w kontenerze, podczas gdy ten uzyskuje realrozmiar
rickyduck
2
Uważam, że zdarzenie ładowania uruchamia się w tej samej pętli zdarzeń, więc setTimout wynoszący 1 milisekundę będzie działał równie dobrze
George Mauer
hhmmm Każdy wie, jak uzyskać wysokość elementu iframe, który jest ukryty w momencie ładowania elementu nadrzędnego. Ta metoda przywraca 0.
JT ...
1
Możesz chcieć documentwysokości, a nie bodywysokości. Używając jQuery możesz go pobrać $(this.contentWindow.document).height().
vpiTriumph
Na starsze, tj. Iframe.contentDocument.body.offsetHeight będzie działać. stackoverflow.com/questions/2684693/…
user1087079
50

Mniej skomplikowaną odpowiedzią jest użycie .contents()elementu iframe. Co ciekawe, zwraca inną wartość niż ta, którą otrzymałem, używając kodu w mojej pierwotnej odpowiedzi, ze względu na wypełnienie ciała, jak sądzę.

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

W ten sposób zrobiłem to do komunikacji między domenami, więc obawiam się, że może to być niepotrzebnie skomplikowane. Najpierw umieściłbym jQuery w dokumencie iFrame; spowoduje to zużycie większej ilości pamięci, ale nie powinno wydłużać czasu ładowania, ponieważ skrypt wystarczy załadować tylko raz.

Użyj jQuery elementu iFrame, aby zmierzyć wysokość treści elementu iframe tak wcześnie, jak to możliwe (onDOMReady), a następnie ustaw wartość skrótu adresu URL na tę wysokość. W dokumencie nadrzędnym dodaj onloadzdarzenie do tagu iFrame, które sprawdzi położenie elementu iframe i wyodrębni potrzebną wartość. Ponieważ onDOMReady zawsze występuje przed zdarzeniem ładowania dokumentu, można być dość pewnym, że wartość zostanie przekazana poprawnie, bez sytuacji wyścigu komplikującej sytuację.

Innymi słowy:

... w 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);

... oraz w dokumencie nadrzędnym:

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 );
Andrzej
źródło
Cześć Andrew, jak dotąd bardzo dobra pomoc tutaj. content () działa świetnie, ale nadal muszę go przetestować za pomocą ogranicznika przepustowości. Może możesz użyć właściwości innerHeight (). Mam problem w FF (OSX) używając twojego rozwiązania wstawiającego wysokość do hasha. Wydaje się, że FF nadal ładuje funkcję getDocumentHeight () w bezokolicznikowej pętli? Safari jest w porządku ..
FFish
Ciekawy. Dodałem kontrolę, która zapobiega ustawieniu skrótu, jeśli istnieje już tam wartość. Być może będziesz musiał to poprawić, jeśli ładujesz Help.php z wartością skrótu (np. <iframe src="../Help.php#introduction" />)
Andrew
Nawiasem mówiąc, zakładając, że możesz dostosować się do różnicy wysokości, prawdopodobnie nie musisz używać skrótu do komunikacji poza ramką iframe. Jeśli używasz metody mieszania, umieszczenie sleep(5)w Help.php powinno być również dobrym sposobem na przetestowanie wszelkich warunków wyścigu. Jeśli element iframe w jakiś sposób uruchomił się onLoadwcześniej onDOMReady, powinien pojawić się tutaj.
Andrew
23

Znalazłem następujące elementy do pracy w Chrome, Firefox i IE11:

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

Gdy zawartość ramek iframe zostanie załadowana, zdarzenie zostanie uruchomione, a wysokość ramek iframe zostanie ustawiona na wysokość jej zawartości. Będzie to działać tylko w przypadku stron w tej samej domenie, w której znajduje się domena iFrame.

Jack Zach Tibbles
źródło
działa dobrze, ale dla szerokości muszę to zrobić w ten sposób lub zawartość zostanie obcięta $ ('iframe'). width ($ ('iframe'). content (). width () + 30);
Geomorillo
@AminGhaderi Działa dobrze dla mnie w przeglądarce Firefox 40.0.3
mixkat
@mixkat ładuję stronę internetową w iframe za pomocą tego rozwiązania i wszystkich rozwiązań w tym temacie, ale dla mnie nie działa! Myślę, że to rozwiązanie działa dla jednej strony i nie działa, gdy wczytujemy kompletną witrynę do elementu iframe. mój angielski jest bardzo słaby, mam nadzieję, że zrozumiesz.
Amin Ghaderi
@AminGhaderi Jeśli mam rację, spodziewasz się, że to zadziała na każdej stronie w Twojej witrynie, ale oczywiście to nie zadziała na wszystkich stronach, ponieważ działa tylko raz, gdy załadujesz ramkę. Więc to zadziała na pierwszej stronie dobrze, ale jeśli chcesz, aby działało na dłuższych stronach, będziesz musiał to zrobić ponownie, albo ładując ramkę ponownie z nową stroną, albo wywołując zawartość. Wysokość w innym miejscu w twój flow
mixkat
9

Kod do zrobienia tego bez jQuery jest obecnie trywialny:

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

Aby odczepić wydarzenie:

frame.removeEventListener('load', syncHeight)
cchamberlain
źródło
3
Ładnie i prosto! Niestety nie działa dla międzydomenowych ramek iframe :(
TimoSolo
3
Tak, pecha. Wykorzystałbym do tego bibliotekę iframe-resizer. Oczywiście musisz mieć kontrolę nad obiema domenami, aby działało.
cchamberlain
6

Nie potrzebujesz do tego jquery wewnątrz elementu iframe, ale ja go używam, ponieważ kod jest o wiele prostszy ...

Umieść to w dokumencie wewnątrz elementu iframe.

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

dodano pięć powyżej, aby wyeliminować pasek przewijania w małych oknach, nigdy nie jest idealny pod względem rozmiaru.

I to w twoim dokumencie nadrzędnym.

function set_size(ht)
{
$("#iframeId").css('height',ht);
}
RkaneKnight
źródło
To również nie zadziała, jeśli wyświetlasz plik PDF w ramce iframe.
Jason Foglia
Przepraszamy, ale Twój przykład „inside frame” jest wyraźnie oparty na jQuery.
T-moty
4

to jest poprawna odpowiedź, która mi pomogła

$(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
źródło
4

prosta jedna linijka zaczyna się od domyślnej minimalnej wysokości i zwiększa do rozmiaru zawartości.

<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
źródło
1

Jest to rozwiązanie wolne od jQuery, które może współpracować ze SPA wewnątrz elementu iframe

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
});
Envil
źródło
1

To jest moje przyjazne dla ES6 podejście bez jquery

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
źródło