Обнаружение загрузки содержимого iframe (кроссбраузерность)

91

Я пытаюсь определить, когда iframe и его содержимое загружены, но мне не очень повезло. Мое приложение вводит данные в текстовые поля в родительском окне и обновляет iframe, чтобы обеспечить «предварительный просмотр в реальном времени».

Я начал со следующего кода (YUI), чтобы определить, когда происходит событие загрузки iframe.

$E.on('preview-pane', 'load', function(){
    previewBody = $('preview-pane').contentWindow.document.getElementsByTagName('body')[0];
}

Preview-pane - это идентификатор моего iframe, и я использую YUI для присоединения обработчика событий. Однако попытка получить доступ к телу в моем обратном вызове (при загрузке iframe) не удается, я думаю, потому что iframe загружается до того, как обработчик событий готов. Этот код работает, если я откладываю загрузку iframe, заставляя php-скрипт, который его генерирует, спать.

По сути, я спрашиваю, каков правильный подход в браузерах для определения того, когда iframe загружен и его документ готов?

Дэвид Снабел-Коунт
источник
1
Начать с YUI - плохая идея (как и с любой другой JS-библиотекой). Зачем? Потому что вы просто не можете знать, какое волшебство творит эта библиотека. Если они не могут полностью поддерживать «загрузку», вам лучше сделать это самостоятельно, используя ясный и читаемый javascript.
Christian
2
Часто можно прочитать исходный код библиотеки @Christian. Я считаю, что это обычно дает вам отличные советы о том, как это сделать самостоятельно, независимо от того, используете ли вы их реализацию или нет.
AJP
@AJP Вы неправильно поняли мою точку зрения. Если вы делаете что-то, в чем не уверены, лучше иметь меньше кода, чтобы было меньше места для ошибок.
Christian
2
Зависит от того, как ты смотришь на это. Я знал, что обработка событий YUI работала в то время, поэтому мне не приходилось беспокоиться об этой части кода. Я также знал, как написать свой собственный обработчик addEvent, не то чтобы он работал лучше, чем YUI в отношении этой проблемы.
Дэвид Снабел-Коунт 06
1
@Nico Вопрос относится к YUI, а $ - это псевдоним обертки YUI Dom.
Дэвид Снабел-Коунт,

Ответы:

73

определить, когда iframe загружен и его документ готов?

Идеально, если вы можете заставить iframe сообщать вам себя из сценария внутри фрейма. Например, он может вызвать родительскую функцию напрямую, чтобы сообщить ей, что она готова. При выполнении кода между кадрами всегда требуется осторожность, поскольку все может происходить в неожиданном порядке. Другой вариант - установить var isready = true; в своей собственной области, и пусть родительский сценарий обнюхивает 'contentWindow.isready' (и, если нет, добавьте обработчик onload).

Если по какой-то причине совместная работа документа iframe нецелесообразна, у вас есть традиционная проблема гонки нагрузки, а именно, что даже если элементы находятся рядом друг с другом:

<img id="x" ... />
<script type="text/javascript">
    document.getElementById('x').onload= function() {
        ...
    };
</script>

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

Способы выхода из гонок:

  1. в IE вы можете использовать свойство readyState, чтобы узнать, загружено ли что-либо;

  2. Если допустимо наличие элемента, доступного только с включенным JavaScript, вы можете создать его динамически, установив функцию события «onload» перед установкой источника и добавлением на страницу. В этом случае он не может быть загружен до установки обратного вызова;

  3. старый способ включить его в разметку:

    <img onload="callback(this)" ... />

Встроенные обработчики «onsomething» в HTML почти всегда являются неправильными, и их следует избегать, но в данном случае иногда это наименее плохой вариант.

бобинс
источник
Спасибо. Мое решение проверяет readyState (если существует), а затем длину элемента body innerHTML, чтобы узнать, загрузился ли он. Если нет, присоединяет обработчик события загрузки. Кажется, работает нормально
Дэвид Снабел-Каунт
8
-1 - инлайновые события не «плохие», это обычное дело. Фактически, встроенные события легче отлаживать и понимать, в отличие от их волшебных аналогов (которые, с другой стороны, легче присоединять, складывать и использовать без проблем).
Christian
1
@Christian, встроенные события также являются лучшим вариантом, когда вам нужно прикрепить событие к каждому элементу очень длинного списка. Поскольку вы уже зацикливаетесь на построении списка на стороне сервера, гораздо эффективнее прикрепить встроенное событие.
haknick
16
@haknick Разве вы не хотите использовать единственный прослушиватель событий в списке и использовать делегат события? Это было бы более эффективно.
Дэвид Снабел-Коунт 07
4
Это не сработает, если iframe является междоменным. Скрипт внутри iframe не может получить доступ к родительскому окну.
Судхир Сомешвара 08
48

См. Это сообщение в блоге. Он использует jQuery, но должен помочь вам, даже если вы его не используете.

Обычно вы добавляете это в свой document.ready()

$('iframe').load(function() {
    RunAfterIFrameLoaded();
});
Кгианнакакис
источник
Интересно, но у меня проблема с событиями загрузки и временем. Я прислушиваюсь к событию загрузки, как указано в этой статье.
Дэвид Снабел-Коунт,
Я пробовал это с console.log. он регистрируется после загрузки iframe.
shorif2000
12

Для тех, кто использует React, обнаружение события загрузки iframe с одинаковым происхождением так же просто, как установка onLoadпрослушивателя событий для элемента iframe.

<iframe src={'path-to-iframe-source'} onLoad={this.loadListener} frameBorder={0} />

Фарзад Ю.З.
источник
Может ли onLoadсобытие запускаться только для iframe того же происхождения?
L_K
2

Для всех, кто использует Ember, это должно работать должным образом:

<iframe onLoad={{action 'actionName'}}  frameborder='0' src={{iframeSrc}} />
Макс Уоллес
источник