jquery получает высоту содержимого iframe при загрузке


85

У меня есть страница справки help.php, которую я загружаю в iframe в main.php. Как я могу получить высоту этой страницы после ее загрузки в iframe?

Я спрашиваю об этом, потому что я не могу установить высоту iframe до 100% или автоматически. Вот почему я думаю, что мне нужно использовать javascript .. Я использую 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>

Содержимое iFrame поступает из того же домена, что и страница, на которой он находится?
Эндрю

да, Эндрю, я хочу использовать iFrame, потому что я использую якоря на странице справки
FFish

Ответы:


102

хорошо, я наконец нашел хорошее решение:

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

Поскольку некоторые браузеры (более старые Safari и Opera) сообщают, что загрузка завершена до рендеринга CSS, вам необходимо установить тайм-аут, очистить и переназначить src 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';
}

это решение отлично работает, поскольку указанное выше просто получает размер из содержимого фреймов в контейнере, в то время как это получает realразмер
rickyduck

2
Я считаю, что событие загрузки запускается в том же цикле событий, поэтому setTimout в 1 миллисекунду будет работать так же хорошо,
Джордж Мауэр,

ххммм Кто-нибудь знает, как получить высоту iframe, скрытого во время загрузки родителя. Этот метод возвращает 0.
JT ...

1
Возможно, вам нужна documentвысота, а не bodyвысота. Используя jQuery, вы можете получить его $(this.contentWindow.document).height().
vpiTriumph

Для более старых версий, то есть iframe.contentDocument.body.offsetHeight будет работать. stackoverflow.com/questions/2684693/…
user1087079

50

Менее сложный ответ - использовать .contents()iframe. Интересно, однако, что он возвращает значение, отличное от того, которое я получил, используя код в моем исходном ответе, из-за заполнения, я полагаю, на теле.

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

Вот как я это сделал для междоменного общения, поэтому я боюсь, что это может быть излишне сложно. Во-первых, я бы поместил jQuery в документ iFrame; это потребует больше памяти, но не должно увеличивать время загрузки, поскольку скрипт необходимо загрузить только один раз.

Используйте jQuery iFrame, чтобы как можно раньше измерить высоту тела iframe (onDOMReady), а затем установите для хэша URL эту высоту. А в родительском документе добавьте onloadсобытие к тегу iFrame, которое будет смотреть на расположение iframe и извлекать нужное значение. Поскольку onDOMReady всегда будет происходить до события загрузки документа, вы можете быть уверены, что значение будет передано правильно, без усложнения состояния гонки.

Другими словами:

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

... и в родительском документе:

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

Привет, Эндрю, пока очень хорошая помощь. Content () отлично работает, но мне все еще нужно протестировать его с помощью регулятора пропускной способности. Возможно, вы можете использовать свойство innerHeight (). У меня проблема в FF (OSX), используя ваше решение, указав высоту в хэше. FF, кажется, продолжает загружать функцию getDocumentHeight () в бесконечном цикле? Safari в порядке ..
FFish 02

Интересно. Я добавил проверку, которая предотвращает установку хэша, если там уже есть значение. Возможно, вам придется настроить это, если вы загружаете Help.php с хеш-значением (например <iframe src="../Help.php#introduction" />)
Эндрю

Кстати, предполагая, что вы можете отрегулировать разницу в высоте, вам, вероятно, не нужно использовать хеш для связи из iframe. Если вы все же используете метод хеширования, добавление sleep(5)файла в Help.php также должно быть хорошим способом тестирования любых условий гонки. Если onLoadраньше iframe каким-то образом сработал onDOMReady, он должен появиться здесь.
Эндрю

24

Я обнаружил, что в Chrome, Firefox и IE11 работает следующее:

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

Когда загрузка содержимого iframes завершится, событие сработает, и оно установит высоту IFrames на высоту его содержимого. Это будет работать только для страниц в том же домене, что и IFrame.


работает нормально, но для ширины я должен сделать это так, иначе содержимое обрезается $ ('iframe'). width ($ ('iframe'). contents (). width () + 30);
Geomorillo

@AminGhaderi У меня отлично работает в firefox 40.0.3
mixkat

@mixkat Я загружаю веб-сайт в iframe через это решение и все решения в этой теме, но для меня это не работает! Я думаю, что эти решения работают для одной страницы и не работают, когда мы полностью загружаем веб-сайт в iframe. у меня очень плохой английский, надеюсь, ты поймешь.
Амин Гадери

@AminGhaderi, если я правильно понял, вы ожидаете, что это сработает для каждой страницы вашего сайта, но, конечно, это не будет работать для всех страниц, так как запускается только один раз, когда вы загружаете фрейм. Таким образом, он будет работать для первой страницы нормально, но затем, если вы хотите, чтобы он работал для более длинных страниц, вам придется сделать это снова, либо снова загрузив фрейм с новой страницей, либо вызвав content.height в какой-то другой момент в ваш поток
mixkat

9

Код для этого без jQuery в настоящее время тривиален:

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

Чтобы отцепить событие:

frame.removeEventListener('load', syncHeight)

3
Красиво и просто! К сожалению, не работает для междоменных
iframe

3
Да уж там не повезло. Я бы использовал для этого библиотеку iframe-resizer. Конечно, вы должны контролировать оба домена, чтобы он работал.
cchamberlain

6

Для этого вам не нужен jquery внутри iframe, но я использую его, потому что код намного проще ...

Поместите это в документ внутри вашего iframe.

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

добавлено пять выше, чтобы убрать полосу прокрутки в маленьких окнах, она никогда не бывает идеальной по размеру.

И это внутри вашего родительского документа.

function set_size(ht)
{
$("#iframeId").css('height',ht);
}

Это также не сработает, если вы отображаете PDF-файл в iframe.
Джейсон Фолья

Извините, но ваш пример «внутри фрейма» явно основан на jQuery.
T-moty

4

это правильный ответ, который сработал для меня

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

4

простой однострочник начинается с минимальной высоты по умолчанию и увеличивается до размера содержимого.

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


2

Принятый ответ $('iframe').loadтеперь приведет к a.indexOf is not a functionошибке. Может быть обновлен до:

$('iframe').on('load', function() {
  // ...
});

Несколько других, похожих на .loadустаревшие, начиная с jQuery 1.8: ошибка «Uncaught TypeError: a.indexOf не является функцией» при открытии нового основного проекта.


1

Это бесплатное решение jQuery, которое может работать со SPA внутри 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
});

1

Это мой дружественный к ES6 вариант без 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`;
});
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.