Jak uzyskać dostęp do nadrzędnego elementu iframe z JavaScript

170

Cóż, mam ramkę iFrame, która wywołuje tę samą stronę domeny. Mój problem polega na tym, że chcę uzyskać dostęp do niektórych informacji z tego nadrzędnego elementu iframe z tej wywoływanej strony (z JavaScript). Jak mogę uzyskać dostęp do tego elementu iframe?

Szczegóły: Istnieje kilka ramek iframe takich jak ta, które mogą mieć załadowaną tę samą stronę, ponieważ programuję środowisko Windows. Zamierzam zamknąć ten iframe, dlatego muszę wiedzieć, który powinienem zamknąć od wewnątrz. Mam tablicę zawierającą odniesienia do tych ramek iframe.

EDYCJA: Tam iframe są generowane dynamicznie

José Leal
źródło
nawet jeśli ramki iframe są generowane dynamicznie, możesz przypisać nowy unikalny identyfikator za pomocą pewnego rodzaju licznika, w końcu nie musisz znać identyfikatora, ale możesz łatwo wyszukiwać, zobacz moją odpowiedź.
Akash Kava

Odpowiedzi:

138

Możesz także ustawić nazwę i identyfikator na równe wartości

<iframe id="frame1" name="frame1" src="any.html"></iframe>

więc będziesz mógł użyć kolejnego kodu wewnątrz strony podrzędnej

parent.document.getElementById(window.name);
Wodny
źródło
16
Może nie jest to oczywiste dla wszystkich, ale za pomocą tej metody można uzyskać dostęp do obiektu biblioteki rodzica (tylko jeśli rodzic już załadował bibliotekę). Przykład: dostęp do jQuery z rodzicem. $ ('# Coś')
Zsolti
1
To rozwiązanie jest zgodne z trybem dziwactw zgodności IE5 +.
Slayner
Nawet w 2016 roku sprawdza się to świetnie jako część rozwiązania problemu drukowania IE zawartości iframezbyt małego. Ale dlaczego to działa? window.namezwraca ciąg. Czym różni się używanie window.nameod zwykłego przekazywania nazwy identyfikatora jako łańcucha, który nie działa)?
Karl
3
Cześć, nie działa z Chrome 59 ..: VM111: 1 Uncaught DOMException: Zablokowano ramce o źródle „ xxx ” dostęp do ramki cross-origin.
Didier68
Chrome widzi pliki w tym samym folderze co cross-origin, jeśli nie ustawiono CORS. Mówią, że to dla bezpieczeństwa. Ustawienie CORS wymaga serwera. Poinformuj użytkowników o konieczności skonfigurowania serwera lub zmiany przeglądarki w przypadku wykrycia przeglądarki Chrome.
90

Po prostu zadzwoń window.frameElementze swojej strony w ramce. Jeśli strona nie jest w ramce, frameElementbędzie null.

W drugą stronę (umieszczenie elementu okna wewnątrz ramy jest mniej trywialne), ale ze względu na kompletność:

/**
 * @param f, iframe or frame element
 * @return Window object inside the given frame
 * @effect will append f to document.body if f not yet part of the DOM
 * @see Window.frameElement
 * @usage myFrame.document = getFramedWindow(myFrame).document;
 */
function getFramedWindow(f)
{
    if(f.parentNode == null)
        f = document.body.appendChild(f);
    var w = (f.contentWindow || f.contentDocument);
    if(w && w.nodeType && w.nodeType==9)
        w = (w.defaultView || w.parentWindow);
    return w;
}
Ian Carter
źródło
2
Dzięki! Działa na IE 6+, FF i Chrome!
rustyx
11
window.frameElementzwraca, nullgdy okno i element iframe mają różne domeny, tj. przesyłanie wiadomości między źródłami.
Qwerty
@Qwerty czy znalazłeś jakieś rozwiązanie?
Ajay Patidar
@AjayPatidar Myślę, że się poddałem. :(
Qwerty
78

Polecam korzystanie z postMessage API .

W swoim iframe zadzwoń:

window.parent.postMessage({message: 'Hello world'}, 'http://localhost/');

Na stronie, którą dołączasz element iframe, możesz nasłuchiwać takich zdarzeń:

window.addEventListener('message', function(event) {
      if(event.origin === 'http://localhost/')
      {
        alert('Received message: ' + event.data.message);
      }
      else
      {
        alert('Origin not allowed!');
      }

    }, false);

Nawiasem mówiąc, możliwe jest również wywoływanie innych okien, a nie tylko ramek iframe.

Przeczytaj więcej o API postMessage na blogu Johna Resigs'a tutaj

Kenneth Lynne
źródło
7
Myślę, że to zdecydowanie najlepsza odpowiedź, <iframe>treść nie musi nic wiedzieć o rodzicu i odwrotnie. Muszą tylko przestrzegać prostej umowy dotyczącej wiadomości. Niesamowite!
mfeineis
1
<iframe> nadal musi znać domenę rodzica, prawda?
Homr Zodyssey
1
@HomrZodyssey Domena nadrzędna jest dostępna tylko jako mechanizm bezpieczeństwa, jeśli nie jest znana, możesz ją ustawić '*'.
Amir Ali Akbari
Użyj '*'na klientach. Każde inne rozwiązanie powoduje błąd w przeglądarce Chrome, która traktuje pliki w folderze klientów jako inne niż to samo źródło, ponieważ serwer nie jest skonfigurowany. To najlepsze i jedyne rozwiązanie: dyn-web.com/tutorials/iframes/postmessage
30

Stare pytanie, ale miałem ten sam problem i znalazłem sposób na uzyskanie ramki iframe. Jest to po prostu kwestia iteracji przez tablicę frames [] okna nadrzędnego i przetestowania contentWindow każdej ramki z oknem, w którym działa twój kod. Przykład:

var arrFrames = parent.document.getElementsByTagName("IFRAME");
for (var i = 0; i < arrFrames.length; i++) {
  if (arrFrames[i].contentWindow === window) alert("yay!");
}

Lub używając jQuery:

parent.$("iframe").each(function(iel, el) {
  if(el.contentWindow === window) alert("got it");
});

Ta metoda oszczędza przypisywanie identyfikatora do każdego elementu iframe, co jest dobre w twoim przypadku, ponieważ są tworzone dynamicznie. Nie mogłem znaleźć bardziej bezpośredniego sposobu, ponieważ nie możesz pobrać elementu iframe za pomocą window.parent - przechodzi bezpośrednio do nadrzędnego elementu okna (pomijając iframe). Dlatego ich przeglądanie wydaje się jedynym sposobem, chyba że chcesz użyć identyfikatorów.

składnik_15939
źródło
1
Aktualizacja: to nie działało dokładnie tak, jak w reklamie i musiałem użyć dokumentu contentWindow.document ===. Nie mam pojęcia dlaczego. Również w niektórych przeglądarkach korzystałem z contentDocument. Cóż, podoba mi się to!
Christophe
1
Przepraszam, co prawda przetestowałem go tylko w Firefoksie. :) Jednak odniosłem sukces używając metody jQuery i contentWindow w wielu przeglądarkach.
składnik_15939
1
Aktualizacja: Dowiedziałem się, że możesz również użyć window.frameElement, ale nie jestem pewien, które przeglądarki to obsługują.
Christophe,
2
Myślę, że tego typu rzeczy już nie działają; pojawia się błąd między źródłami.
Andrew Mao
@AndrewMao pytanie dotyczy dokumentów tego samego pochodzenia, więc nie ma powodu, aby uzyskać problemy z różnymi źródłami.
Christophe
21

możesz użyć, parentaby uzyskać dostęp do strony nadrzędnej. Aby uzyskać dostęp do funkcji, byłoby to:

var obj = parent.getElementById('foo');
kemiller2002
źródło
1
Kevin, problem polega na tym, żeby ZNAĆ identyfikator. Mam kilka ramek iframe i chcę uzyskać do nich dostęp z kodu wewnątrz
José Leal
Nadal otrzymujesz komunikat „Zablokowano ramkę o pochodzeniu” inny-localhost: 8000 „przed dostępem do ramki pochodzącej z różnych źródeł”.
user2568374
13

Po ustawieniu id elementu iframe możesz uzyskać dostęp do elementu iframe z dokumentu wewnętrznego, jak pokazano poniżej.

var iframe = parent.document.getElementById(frameElement.id);

Działa dobrze w IE, Chrome i FF.

Akash Kava
źródło
Wydaje się, że jest to zawiły sposóbvar iframe = frameElement
Oriol
frameElement zwraca obiekt w bieżącym kontekście okna, ale parent.document.getElementById (frameElement.id) zwraca obiekt w kontekście okna nadrzędnego, nie możesz uruchomić funkcji javascript okna nadrzędnego za pomocą frameElement, wypróbuj to w jsfiddle i daj mi przykład, jeśli możesz .
Akash Kava
6

Może po prostu użyj

window.parent

do elementu iframe, aby uzyskać wywołującą ramkę / okna. Jeśli masz wiele ramek wywołujących, możesz użyć

window.top
Clawfire
źródło
3

Spróbuj tego, w swojej ramce nadrzędnej skonfiguruj swoje IFRAME'y w ten sposób:

<iframe id="frame1" src="inner.html#frame1"></iframe>
<iframe id="frame2" src="inner.html#frame2"></iframe>
<iframe id="frame3" src="inner.html#frame3"></iframe>

Zauważ, że identyfikator każdej ramki jest przekazywany jako kotwica w src.

następnie w swoim wewnętrznym html możesz uzyskać dostęp do identyfikatora ramki, w której jest ładowana, poprzez location.hash:

<button onclick="alert('I am frame: ' + location.hash.substr(1))">Who Am I?</button>

wtedy możesz uzyskać dostęp do parent.document.getElementById (), aby uzyskać dostęp do tagu iframe z wnętrza elementu iframe

Mark Porter
źródło
Tak, byłoby to najbardziej logiczne rozwiązanie, ale czasami muszę zmienić src elementu iframe ... i przekazać ten parametr hash lub GET, każde żądanie nie jest dobre ..
José Leal
dlaczego źle jest przekazywać hash za każdym razem? Jest widoczny tylko dla przeglądarki, a nie dla serwera i nie wpływa na buforowanie, tak jak zrobiłby to parametr get.
Mark Porter
-1
// just in case some one is searching for a solution
function get_parent_frame_dom_element(win)
{
    win = (win || window);
    var parentJQuery = window.parent.jQuery;
    var ifrms = parentJQuery("iframe.upload_iframe");
    for (var i = 0; i < ifrms.length; i++)
    {
        if (ifrms[i].contentDocument === win.document)
            return ifrms[i];
    }
    return null;
}
Alex
źródło