Определить DOMContentLoaded в iframe

Я был удивлен, обнаружив, что следующее не работает, поскольку событие DOMContentLoaded не запускается (this.els является объектом элементов).

this.els.stage_ifr.prop('src', 'templates/'+ee.globals.creating+'/item'+this.id);
this.els.stage_ifr[0].addEventListener('DOMContentLoaded', function() {
    alert('loaded!');
}, false);

Страница загружается в iframe нормально, но обратного вызова нет. Уровень DOM ноль onloadОднако работает.

this.els.stage_ifr[0].onload = function() { alert('loaded!'); }; //<-- fires

Обходной путь - подготовить глобально доступный отложенный объект jQuery на родительской странице и разрешить его с помощью события DOM-ready, инициированного со страницы, вызываемой в iframe, вместо прослушивания DOM-ready от родительского объекта.

Страничка Паранта:

dfd = new $.Deferred;
dfd.done(function() { alert("frame page's DOM is ready!"); });

Рамка страницы:

$(function() { window.parent.dfd.resolve(); });

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

3 ответа

Решение

В процессе ответа на этот вопрос я обнаружил причину вашего DOMContentLoaded слушатель событий не работает. Мне кажется, у вас есть две проблемы.

Во-первых, вы пытаетесь слушать DOMContentLoaded событие на самом iFrame. Это не событие iFrame. Это событие документа. Таким образом, вы должны обратиться к iFrame, чтобы получить contentWindow, а затем получить документ из этого. Это приводит ко второму вопросу.

Во-вторых, когда iFrame создается впервые, у него есть фиктивная document в нем, который НЕ тот же документ, который будет в конечном итоге там, когда динамический контент загружается через .src приписывать. Итак, даже если вы сделали:

this.els.stage_ifr.contentWindow.document

чтобы получить документ в iFrame, он не обязательно будет правильным документом и, следовательно, DOMContentLoaded событие не сработает (я видел такое поведение в Chrome).


MDN говорит, что можно слушать DOMFrameContentLoaded событие на самом iFrame, и это будет соответствовать тому, когда базовый документ действительно получает DOMContentLoaded, К сожалению, я не могу заставить это событие работать ни в одном браузере. Итак, в данный момент единственный обходной путь, о котором я знаю, - это инициировать событие загрузки изнутри самого iFrame, где он может прослушивать свой собственный DOMContentLoaded событие (оно может вызвать родительское окно, если это необходимо) или просто прослушать load событие на объекте iFrame и знать, что он не будет срабатывать, пока не будут загружены такие ресурсы, как таблицы стилей и изображения в iFrame.


В любом случае, я подумал, что объясню кое-что из того, что происходит с вашим исходным кодом, и предложу другое решение, даже если этот вопрос был опубликован более года назад (хотя так и не получил ответа).


Обновить:

Я разработал метод отслеживания DOMContentLoaded для iFrame, загруженного с тем же источником, что и его родитель. Вы можете увидеть код здесь.

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

var iframe = document.getElementById("app-frame-id");
iframe.contentWindow.addEventListener("DOMContentLoaded", onFrameDOMContentLoaded, true);
function onFrameDOMContentLoaded () { 
     console.log("DOMContentLoaded");
};

Если ваша страница и iframe находятся в одном домене, вам нужно дождаться запуска исходной страницы.DOMContentLoaded сначала, затем прикрепите DOMContentLoaded прослушиватель событий в iframe Window (не Document).

Учитывая, что у вас есть iframe следующим образом,

<iframe id="iframe-id" name="iframe-name" src="..."></iframe>

следующий фрагмент позволит вам подключиться к iframe DOMContentLoaded событие:

document.addEventListener('DOMContentLoaded', function () {
    var iframeWindow = frames['iframe-name'];
    // var iframeWindow = document.querySelector('#iframe-id').contentWindow
    // var iframeWindow = document.getElementById('iframe-id').contentWindow

    iframeWindow.addEventListener('DOMContentLoaded', function () {
        console.log('iframe DOM is loaded!');
    });
});

Это может быть больше взломать, но помог мне решить аналогичную проблему.

Я слушаю onmouseenter содержимого кадра сейчас.

Это событие срабатывает впереди load (если пользователь перемещает мышь). Но, как и в моем случае, мне нужно событие для инициализации контекстного меню, так или иначе, использование мыши было предварительным условием.

Он даже срабатывает, когда содержимое фрейма изменяется под мышью.

Другие вопросы по тегам