Как получить доступ к родительскому Iframe из JavaScript

170

Ну, у меня есть IFrame, который вызывает ту же страницу домена. Моя проблема в том, что я хочу получить доступ к некоторой информации из этого родительского Iframe с этой вызываемой страницы (из JavaScript). Как я могу получить доступ к этому Iframe?

Детали: Есть несколько таких же фреймов, которые могут загружать одну и ту же страницу, потому что я программирую среду Windows. Я намерен закрыть этот Ифраме, поэтому мне нужно знать, что мне следует закрыть из него. У меня есть массив, хранящий ссылки на эти Iframes.

РЕДАКТИРОВАТЬ: Там iframes генерируются динамически

Хосе Лил
источник
даже если iframes генерируются динамически, вы можете назначить новый уникальный идентификатор, используя какой-то счетчик, наконец, вам не нужно знать ID, но вы можете легко искать, см. мой ответ.
Акаш Кава

Ответы:

138

Также вы можете установить имя и идентификатор на равные значения

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

так что вы сможете использовать следующий код на дочерней странице

parent.document.getElementById(window.name);
водный
источник
16
Возможно, это не очевидно для всех, но с помощью этого метода вы можете получить доступ к объекту библиотеки родителя (только если родитель уже загрузил библиотеку). Пример: доступ к jQuery с родителем. $ ('
#Thing
1
Это решение совместимо с режимом совместимости IE5 +.
Слайнер
Даже в 2016 году это прекрасно работает как часть решения проблемы печати IE содержимого iframeслишком маленького размера. Но почему это работает? window.nameвозвращает строку Чем отличается использование window.nameот передачи имени id в виде строки, которая не работает?)?
Карл
3
Привет, это не работает с Chrome 59 ..: VM111: 1 Uncaught DOMException: заблокирован фрейм с происхождением " xxx " от доступа к фрейму перекрестного происхождения.
Didier68
Chrome видит файлы в той же папке, что и кросс-источник, если не установлен CORS. Они говорят, что это для безопасности. Для настройки CORS нужен сервер. Дайте пользователям сообщение, чтобы настроить сервер или изменить браузер, если обнаружен Chrome.
90

Просто позвоните window.frameElementсо страницы в рамке. Если страница не в рамке, то frameElementбудет null.

Другой способ (получить элемент window внутри фрейма менее тривиально), но для полноты:

/**
 * @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;
}
Ян Картер
источник
2
Спасибо! Работает на IE 6+, FF и Chrome!
rustyx
11
window.frameElementВозвращается, nullкогда window и iframe имеют разные домены, то есть обмен сообщениями между источниками.
Qwerty
@ Qwerty, вы нашли какое-нибудь решение?
Аджай Патидар
@ AjayPatidar Я думаю, что сдался. :(
Qwerty
78

Я бы порекомендовал использовать API postMessage .

В своем фрейме звоните:

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

На странице вы включаете iframe, вы можете прослушивать такие события:

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

    }, false);

Кстати, также можно делать звонки в другие окна, а не только в фреймы.

Узнайте больше об API postMessage в блоге Джона Резигса здесь

Кеннет Линн
источник
7
Я думаю, что это, безусловно, лучший ответ, <iframe>содержание не должно ничего знать о родителе и наоборот. Они только должны подчиняться простому контракту сообщения. Потрясающие!
mfeineis
1
<Iframe> все еще должен знать домен родителя, верно?
Homr Zodyssey
1
@HomrZodyssey Родительский домен доступен только в качестве механизма безопасности, если он неизвестен, его можно установить '*'.
Амир Али Акбари
Используйте '*'на клиентах. Любые другие решения выдают ошибку в браузере Chrome, считая файлы в папке клиентов не принадлежащими к тому же источнику, поскольку сервер не настроен. Это лучшее и единственное решение: dyn-web.com/tutorials/iframes/postmessage
30

Старый вопрос, но у меня была такая же проблема, и я нашел способ получить iframe. Это просто вопрос перебора массива frames [] родительского окна и проверки содержимого окна каждого фрейма относительно окна, в котором выполняется ваш код. Пример:

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

Или, используя jQuery:

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

Этот метод сохраняет назначение идентификатора для каждого iframe, что хорошо в вашем случае, поскольку они создаются динамически. Я не смог найти более прямой путь, так как вы не можете получить элемент iframe с помощью window.parent - он идет прямо к родительскому элементу окна (пропуская iframe). Так что циклический просмотр их кажется единственным способом, если только вы не хотите использовать идентификаторы.

ingredient_15939
источник
1
Обновление: это не сработало так, как рекламировалось, и мне пришлось использовать contentWindow.document === документ. Понятия не имею почему. Также в некоторых браузерах я использовал contentDocument. Ну, мне это нравится!
Кристоф
1
Извините, по общему признанию я только проверял это в Firefox. :) Однако я успешно использовал метод jQuery и contentWindow в нескольких браузерах.
ингридиент_15939
1
Обновление: я узнал, что вы также можете использовать window.frameElement, но я не уверен, какие браузеры его поддерживают.
Кристоф
2
Я не думаю, что этот тип вещей больше работает; Вы получаете перекрестную ошибку.
Андрей Мао
@ AndrewMao вопрос касается документов того же происхождения, так что нет причин получать проблемы с другим происхождением.
Кристоф
21

Вы можете использовать parentдля доступа к родительской странице. Таким образом, для доступа к функции это будет:

var obj = parent.getElementById('foo');
kemiller2002
источник
1
Кевин, проблема в том, чтобы знать идентификатор. У меня есть несколько Iframes, и я хочу получить к ним доступ из кода внутри
Хосе Лил
По-прежнему получайте «Заблокирован фрейм с источником» other-localhost: 8000 «от доступа к фрейму кросс-источника».
user2568374
13

Как только идентификатор iframe установлен, вы можете получить доступ к iframe из внутреннего документа, как показано ниже.

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

Хорошо работает в IE, Chrome и FF.

Акаш Кава
источник
Это кажется запутанным способом сделатьvar iframe = frameElement
Oriol
frameElement возвращает объект в текущем контексте окна, но parent.document.getElementById (frameElement.id) возвращает объект в контексте родительского окна, вы не можете запускать функции javascript родительского окна с помощью frameElement, попробуйте его в jsfiddle и приведите мне пример, если можете ,
Акаш Кава
6

Может быть, просто использовать

window.parent

в ваш фрейм, чтобы получить вызывающий фрейм / окна. Если у вас было несколько кадров вызова, вы можете использовать

window.top
Clawfire
источник
3

Попробуйте это, в родительском фрейме установите ваши IFRAME как это:

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

Обратите внимание, что идентификатор каждого кадра передается как привязка в src.

затем в вашем внутреннем html вы можете получить доступ к идентификатору кадра, в который он загружен, через location.hash:

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

Затем вы можете получить доступ к parent.document.getElementById () для доступа к тегу iframe изнутри iframe.

Марк Портер
источник
Да, это было бы наиболее логичным решением, но иногда мне нужно изменить src iframe ... и передавать этот хэш или параметр GET каждый запрос не очень хорошо ..
Хосе Лил
почему плохо каждый раз передавать хеш? Он виден только браузеру, а не серверу, и не влияет на кэширование, как параметр get.
Марк Портер
-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
источник