Wywołanie funkcji okna nadrzędnego z ramki iframe

282

Chcę wywołać funkcję JavaScript okna nadrzędnego z elementu iframe.

<script>
    function abc()
    {
        alert("sss");
    }
</script>

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>
Arjun Singh
źródło
1
Nie będę w stanie nic teraz pokazać (2016), nie wiem, czy starsza altana w ogóle by to wspierała
Weijing Jay Lin

Odpowiedzi:

438
<a onclick="parent.abc();" href="#" >Call Me </a>

Zobacz window.parent

Zwraca odniesienie do elementu nadrzędnego bieżącego okna lub ramy pomocniczej.

Jeśli okno nie ma elementu nadrzędnego, jego właściwość nadrzędna jest odniesieniem do samego siebie.

Gdy okno jest ładowany w sposób <iframe>, <object>lub <frame>jego rodzic jest okno z elementem osadzającym okno.

Rahul
źródło
17
Zawsze należy brać pod uwagę, że dokument nadrzędny i dokument iframe muszą pasować do protokołu i nazwy domeny. Jeśli tak się nie stanie, pojawi się błąd bezpieczeństwa, ponieważ nie można wykonywać skryptów między domenami.
a4bike
Zastanawiam się, który z nich alertzostanie przywołany; alertfunkcja rodzica lub funkcja iframe alert, w przypadku gdy parent.abc();jest wywoływana w iframe?
Prakhar Mishra
@PrakharMishra Nie myl się. rodzic oznacza rodzic.
Sahu V Kumar
3
@ a4bike dla takich scenariuszy, window.postMessage()(lub window.parent.postMessage()) istnieje. Sprawdź @Andrii odpowiedź
Fr0zenFyr
81

Niedawno musiałem dowiedzieć się, dlaczego to też nie zadziałało.

Skrypt javascript, do którego chcesz zadzwonić z elementu iframe dziecka, musi znajdować się w głowie rodzica. Jeśli jest w treści, skrypt nie jest dostępny w zasięgu globalnym.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="parent.abc();" href="#">Click Me</a>
    </iframe>
</body>

Mam nadzieję, że pomoże to każdemu, kto ponownie natknie się na ten problem.

Ash Clarke
źródło
1
Żadna z technik wymienionych w tym poście nie działa w Chrome. Jakieś rozwiązania tego?
Kumar Kush
3
Jeśli dobrze pamiętam, nie mogę sprawić, aby działało zgodnie z oczekiwaniami, jeśli element iframe miał inną domenę niż element nadrzędny. Niestety nie jest to rozwiązanie, ale może wyjaśniać, dlaczego nie działa.
Ash Clarke
1
Tak. Wiem, że dzieje się tak z powodu różnych domen, ale czy nie ma na to sposobu?
Kumar Kush
1
Właśnie opublikowałem, co może być obejściem problemu. Spójrz na drugą odpowiedź.
Ash Clarke
1
Zgodnie z tymi samymi regułami określania zasad pochodzenia (patrz: en.wikipedia.org/wiki/... ) subdomeny są uważane za inną nazwę hosta niż subdomena domeny. Jeśli jeszcze tego nie zrobiłeś, możesz spróbować ustawić document.domain w subdomenie?
Ash Clarke
73

Window.postMessage ()

Ta metoda pozwala bezpiecznie cross-origin komunikację.

A jeśli masz dostęp do kodu strony nadrzędnej, można wywołać dowolną metodę nadrzędną, a także dowolne dane można przekazać bezpośrednio Iframe. Oto mały przykład:

Strona nadrzędna:

if (window.addEventListener) {
    window.addEventListener("message", onMessage, false);        
} 
else if (window.attachEvent) {
    window.attachEvent("onmessage", onMessage, false);
}

function onMessage(event) {
    // Check sender origin to be trusted
    if (event.origin !== "http://example.com") return;

    var data = event.data;

    if (typeof(window[data.func]) == "function") {
        window[data.func].call(null, data.message);
    }
}

// Function to be called from iframe
function parentFunc(message) {
    alert(message);
}

Kod iframe:

window.parent.postMessage({
    'func': 'parentFunc',
    'message': 'Message text from iframe.'
}, "*");
// Use target origin instead of *

AKTUALIZACJE:

Uwaga bezpieczeństwa:

Zawsze podawaj określony cel ORIGIN, NIE *, jeśli wiesz, gdzie powinien znajdować się dokument drugiego okna. Niepodanie konkretnego celu ujawnia dane, które wysyłasz do dowolnej zainteresowanej złośliwej strony (komentarz ZalemCitizen ).

Bibliografia:

Andrii Verbytskyi
źródło
1
Wolę używać tego niż innych. Zwłaszcza, że ​​bardziej sensowne jest używanie ramek iframe w dokumentach krzyżowych (chociaż programiści często używają ramek iframe) i biorąc pod uwagę szerokie wsparcie dla tej funkcji w przeglądarkach.
Fr0zenFyr
1
Dzięki! Zawsze muszę spędzać godzinę lub dłużej, wracając i badając, jak wykonać przesyłanie wiadomości za pomocą skomplikowanych, pełnych przykładów. To działało w 60 sekund. Dzięki za przykład, który jest zwięzły i na temat.
RandallTo 17.01.19
2
warto to podnieść (z dokumentów internetowych MDN ): Zawsze podaj konkretny celOrigin, a nie *, jeśli wiesz, gdzie powinien znajdować się dokument drugiego okna.
Niepodanie
20

Zamieściłem to jako osobną odpowiedź, ponieważ nie ma to związku z moją istniejącą odpowiedzią.

Ten problem ostatnio pojawił się ponownie w celu uzyskania dostępu do elementu nadrzędnego z elementu iframe odwołującego się do poddomeny, a istniejące poprawki nie działały.

Tym razem odpowiedzią było zmodyfikowanie dokumentu. Domena strony nadrzędnej i elementu iframe, aby były takie same. To oszuka te same kontrole zasad pochodzenia że będą one współistnieć w dokładnie tej samej domenie (poddomeny są uważane za innego hosta i nie przejdą tego samego testu zasad pochodzenia).

Wstaw następujące elementy do <head>strony w elemencie iframe, aby dopasować do domeny nadrzędnej (dostosuj do swojego typu dokumentu).

<script>
    document.domain = "mydomain.com";
</script>

Pamiętaj, że spowoduje to zgłoszenie błędu na rozwój hosta lokalnego, więc użyj poniższej kontroli, aby uniknąć błędu:

if (!window.location.href.match(/localhost/gi)) {
    document.domain = "mydomain.com";
} 
Ash Clarke
źródło
a co z testowaniem tego w localhost? jakieś obejście tego?
Umesh Awasthi
Zobacz: „Należy pamiętać, że spowoduje to błąd w rozwoju lokalnego hosta, dlatego należy wykonać następujące sprawdzenie, aby uniknąć błędu”
Ash Clarke
2
Warto zauważyć, że (przynajmniej w Google Chrome) zarówno dokument nadrzędny, jak i podrzędny MUSI USTAWIĆ dokument.domena, nawet jeśli jeden z nich jest już „poprawny”! Przykład: rodzic jest example.comiframe abc.example.com, wtedy zarówno rodzic, jak i iframe muszą zadzwonićdocument.domain = "example.com"
KillerX
Tak, to prawda. Napisałem tutaj literówkę: „strona w ramce iframe ma być taka sama”. powinna być „strona i iframe, aby były takie same”. ..... Dzięki!
Ash Clarke
dla if () dlaczego po prostu nie używałbyś if (document.domain! = "mydomain.com"? Ponadto, jestem zdezorientowany, czy <script> idzie w oknie nadrzędnym czy w ramce iFrame? Również ustawiając document.domain w iFrame generuje „Nie można ustawić właściwości„ domain ”w„ Document ”:„ localhost ”nie jest przyrostkiem„ sc-localhost ”.
user2568374
18

Możesz użyć

window.top

patrz poniżej.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="window.top.abc();" href="#">Click Me</a>
    </iframe>
</body>
Vinothkumar Arputharaj
źródło
Podczas próby wywołania parent.custom_function (); z iframe nie działa możesz znaleźć window.top.custom_function (); będzie działać. Działa dla mnie z jakiegoś dziwnego powodu. Moje javascripts w oknie nadrzędnym są osadzone w stopce, czytam gdzieś, że włączenie plików javascript w stopce powoduje problem, że parent.custom_function () nie działa.
Friso Horstman
@Vothothkumar, jedno pytanie, które jest różnicą między wywołaniem „window.top.abc ()” niż wywołaniem tylko „abc ()”, z góry dziękuję =)
Zilev av
@Zilev av Cały punkt tego wątku wywołuje funkcję w dokumencie nadrzędnym z podrzędnego elementu iframe. To jest różnica. Wywołanie abc()działałoby tylko wtedy, gdy function abc()zostało zadeklarowane w ramce iframe, a nie na stronie nadrzędnej. window.top.abc()wyłamuje się z elementu iframe w dokumencie nadrzędnym.
Sean Kendle,
3

Kolejny dodatek dla tych, którzy go potrzebują. Rozwiązanie Ash Clarke nie działa, jeśli używają różnych protokołów, więc upewnij się, że jeśli używasz SSL, twoja ramka iframe również używa SSL, albo spowoduje to uszkodzenie funkcji. Jego rozwiązanie zadziałało jednak w przypadku samych domen, więc dziękuję za to.

Devon
źródło
2

Rozwiązanie podane przez Ash Clarke dla poddomen działa świetnie, ale pamiętaj, że musisz dołączyć document.domain = "mydomain.com"; zarówno w nagłówku strony iframe, jak i nagłówku strony nadrzędnej, jak podano w linku , sprawdza to samo zasady pochodzenia

Ważnym rozszerzeniem tej samej zasady pochodzenia zaimplementowanej dla dostępu JavaScript DOM (ale nie dla większości innych odmian sprawdzania tego samego pochodzenia) jest to, że dwie witryny współdzielące wspólną domenę najwyższego poziomu mogą zdecydować się na komunikację pomimo niepowodzenia „tego samego hosta” sprawdź, ustawiając wzajemnie odpowiednią właściwość DOM document.domain DOM na ten sam kwalifikowany prawy fragment bieżącej nazwy hosta. Na przykład jeśli http://en.example.com/ i http://fr.example.com/ oba ustawią document.domain na „example.com”, od tego momentu będą one uważane za to samo pochodzenie dla cel manipulacji DOM.

Frato
źródło
Tak, to prawda. Napisałem tutaj literówkę: „strona w ramce iframe ma być taka sama”. powinna być „strona i iframe, aby były takie same”. ..... Dzięki!
Ash Clarke
co powiesz na uruchamianie plików na komputerze lokalnym? Jaka jest wartość document.domain?
Raptor
Będzie to localhostlub adres IP urządzenia (zazwyczaj 127.0.0.1), w zależności od tego, co znajduje się w pasku adresu url.
Ash Clarke,
2

Parent.abc () będzie działać tylko w tej samej domenie ze względów bezpieczeństwa. wypróbowałem to obejście i mój działał idealnie.

<head>
    <script>
    function abc() {
        alert("sss");
    }

    // window of the iframe
    var innerWindow = document.getElementById('myFrame').contentWindow;
    innerWindow.abc= abc;

    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="abc();" href="#">Click Me</a>
    </iframe>
</body>

Mam nadzieję że to pomoże. :)

Seph Remotigue
źródło
Jest to tak naprawdę tylko wykorzystanie dokumentu iframe, co powoduje ogromne komplikacje, jeśli trzeba odwoływać się do elementów sterujących w formularzu nadrzędnym.
Paul
1

W przeglądarce Firefox i Chrome możesz używać:

<a href="whatever" target="_parent" onclick="myfunction()">

Jeśli moja funkcja jest obecna zarówno w ramce iframe, jak i w elemencie macierzystym, zostanie wywołana funkcja nadrzędna.

płatek śniegu
źródło
to nie działa. Oto moje demo: dotku.github.io/tech/html/iframe/iframe_function_container.html
Weijing Jay Lin
Jak stwierdził Ash Clarke, javascript, do którego chcesz zadzwonić od dziecka iframe, musi znajdować się w głowie rodzica.
płatek śniegu
Akceptowana odpowiedź nie wymaga, aby skrypt był w głowie. Nie testowałem, czy to rozwiązanie nie wymaga już, aby skrypt był w głowie, czy nie.
Guy Schalnat,
0

Chociaż niektóre z tych rozwiązań mogą działać, żadne z nich nie przestrzega najlepszych praktyk. Wielu przypisuje zmienne globalne i może się zdarzyć, że wywołujesz wiele zmiennych nadrzędnych lub funkcji, co prowadzi do zaśmieconej, wrażliwej przestrzeni nazw.

Aby tego uniknąć, użyj wzorca modułu. W oknie nadrzędnym:

var myThing = {
    var i = 0;
    myFunction : function () {
        // do something
    }
};

var newThing = Object.create(myThing);

Następnie w ramce iframe:

function myIframeFunction () {
    parent.myThing.myFunction();
    alert(parent.myThing.i);
};

Jest to podobne do wzorców opisanych w rozdziale Dziedziczenie przełomowego tekstu Crockforda „Javascript: The Good Parts”. Możesz także dowiedzieć się więcej na stronie w3 o najlepszych praktykach Javascript. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

William J. Littlefield
źródło