2013-06-06 14 views
9

Zaskoczyło mnie, że poniższe elementy nie działają, o ile zdarzenie DOMContentLoaded nie zostanie wywołane (this.els jest obiektem elementów).Wykryj obiekt DOMContentLoaded w elemencie iframe

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

Strona wczytuje się do elementu iframe, ale bez wywołania zwrotnego. Zero poziomu DOM onload działa.

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

Rozwiązaniem jest przygotowanie globalnie dostępnej obiekt jQuery odroczona strony nadrzędnej i rozwiązać go za pomocą zdarzenia DOM gotowy opalanego ze strony o nazwie do iframe, zamiast słuchania dla DOM-ready z rodzic.

Paraent strona: strona

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

Rama:

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

jednak dobrze byłoby wiedzieć, co się dzieje z pierwszym podejściu ...

+1

Wyjątkowo udostępniam łącze do MSDN: [element iframe] (http://msdn.microsoft.com/en-us/library/ms535258%28v=vs.85%29.aspx). Jak można przeczytać na tej stronie, 'DOMContentLoaded' nie może być dołączony do' iframe'. – Teemu

+0

Interesujące - powinienem był pomyśleć, że to było w porządku, pod warunkiem, że ramka jest tej samej domeny. Jeśli to rzeczywiście jest sprawa zamknięta, możesz ją opublikować jako odpowiedź, a ja to zaakceptuję. – Utkanos

+0

Możesz spróbować dołączyć 'DOMContentLoaded' (tylko metodę' document') do 'stage_ifr [0] .contentDocument', po prostu nie jestem pewien, czy w danym momencie byłaby potrzebna ... – Teemu

Odpowiedz

12

W procesie odpowiadając this question , Odkryłem powód, dla którego Twój detektor zdarzeń DOMContentLoaded nie działa. Wydaje mi się, że masz dwie problemy.

Najpierw próbujesz odsłuchać wydarzenie DOMContentLoaded w samym iFrame. To nie jest wydarzenie iFrame. To wydarzenie dokumentalne. Musisz więc sięgnąć do iFrame, aby pobrać contentWindow, a następnie pobrać dokument z tego. To prowadzi do drugiego numeru.

Po drugie, po utworzeniu elementu iFrame ma on atrapę document, która nie jest tym samym dokumentem, który ostatecznie będzie tam, gdy zawartość dynamiczna zostanie załadowana za pomocą atrybutu .src. Tak więc, nawet jeśli nie:

this.els.stage_ifr.contentWindow.document 

dostać dokument w iframe, to niekoniecznie musi być odpowiedni dokument, a więc zdarzenie DOMContentLoaded nie zadziała na niego (widziałem to zachowanie w Chrome).


MDN mówi, że można wykrywać zdarzenie DOMFrameContentLoaded na samej iFrame i będzie odpowiadać, gdy dokument będący podstawą rzeczywiście dostaje DOMContentLoaded. Niestety, nie mogę uruchomić tego zdarzenia w żadnej przeglądarce. W tej chwili, jedyną opcją, o której wiem, jest wyzwolenie zdarzenia obciążenia wewnątrz samej ramki iFrame, gdzie może ona wysłuchać własnego zdarzenia DOMContentLoaded (może wywołać okno główne, jeśli zajdzie taka potrzeba) lub po prostu posłuchaj zdarzenia load na obiekcie iFrame i pamiętaj, że nie zostanie ono uruchomione, dopóki nie zostaną załadowane zasoby, takie jak arkusze stylów i obrazy w ramce iFrame.


Zresztą myślałem, że wyjaśnić niektóre, co się dzieje z kodem początkowym i oferują inne rozwiązanie, chociaż ta kwestia została wysłana ponad rok temu (choć nigdy nie odpowiedział).


Aktualizacja:

Mam opracowali metodę śledzenia DOMContentLoaded dla iFrame załadowany z tego samego pochodzenia co jego rodzica. Możesz zobaczyć kod here.

+0

Już zadawałem sobie pytanie, dlaczego 'readyState' jest zawsze' completed' w Chrome. Teraz wiem, że to dlatego, że Chrome ustawia pusty dokument i tworzy aktualny dokument iframe (powiązany z atrybutem src). Takie złe zachowanie, gdyby Chrome obsługiwał to tak jak inne przeglądarki, moglibyśmy po prostu użyć 'readyState'. – dude

+0

http://stackoverflow.com/a/36155560/3894981 – dude

+0

'DOMFrameContentLoaded' to nie tylko [zdarzenie związane z Mozillą] (https://developer.mozilla.org/en-US/docs/Web/Events#Mozilla -specific_events), ale także "zdarzenie specyficzne dla dodatku", które "nigdy nie jest narażone na zawartość internetową i może być używane tylko w kontekście zawartości chrome". –

5

Po wypróbowaniu różnych opcji znalazłem, że następujący kod działa dla mnie:

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

To nie działa po zmianie źródła elementu iframe. –

+0

Wydaje się, że działa dla mnie. Ale czy mógłbyś opisać, co to dokładnie robi i dlaczego nie przypisujesz tego zdarzenia do właściwości dokumentu 'contentWindow'? – dude

1

To może być bardziej hack, ale pomógł mi rozwiązać podobny problem.

Słucham teraz dla zawartości ramki onmouseenter.

To wydarzenie uruchamia się przed load (jeśli użytkownik poruszy myszą). Ale tak jak w moim przypadku potrzebuję zdarzenia do zainicjowania menu kontekstowego, używanie myszki było warunkiem koniecznym.

Wywołuje nawet, gdy zawartość ramki zmienia się pod kursorem myszy.

+0

Interesujące podejście. Dzięki za heads up. – Utkanos