По сути, у меня есть iframe, встроенный в страницу, а у iframe есть несколько подпрограмм JavaScript, которые мне нужно вызывать с родительской страницы.
Теперь обратное довольно просто, вам нужно только вызвать parent.functionName(), но, к сожалению, мне нужно прямо противоположное.
Обратите внимание, что моя проблема заключается не в изменении источника URLiframe, а в вызове функции, определенной в iframe.
Обратите внимание, что при отладке вы можете делать такие вещи, как window.location.href или parent.location.href, чтобы просмотреть URL-адрес iframe, если вы хотите убедиться, что у вас есть ссылка на iframe, который вы ищете.
См. Ответ @le dorfier ... отлично сработал для меня.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


У Quirksmode был опубликовать на этом.
Поскольку страница теперь повреждена и доступна только через archive.org, я воспроизвел ее здесь:
IFrames
На этой странице я даю краткий обзор доступа к iframe со страницы, на которой они находятся. Неудивительно, что есть некоторые соображения относительно браузера.
Iframe - это встроенный фрейм, фрейм, который, хотя и содержит полностью отдельную страницу с собственным URL-адресом, тем не менее помещается внутри другой HTML-страницы. Это дает очень хорошие возможности в веб-дизайне. Проблема в том, чтобы получить доступ к iframe, например, чтобы загрузить в него новую страницу. На этой странице объясняется, как это сделать.
Рамка или объект?
Фундаментальный вопрос заключается в том, рассматривается ли iframe как фрейм или как объект.
top.frames[1].frames[2] и т. д.). Подходит ли iframe в эту иерархию фреймов?document.getElementById('theiframe')) для доступа к нему.
Как правило, браузеры допускают оба представления для «реальных» (жестко запрограммированных) iframe, но сгенерированные iframe не могут быть доступны как фреймы.Атрибут NAME
Самое важное правило - дать любому iframe, который вы создаете, атрибут name, даже если вы также используете id.
<iframe src = "iframe_page1.html"
id = "testiframe"
name = "testiframe"></iframe>
Большинству браузеров требуется атрибут name, чтобы сделать iframe частью иерархии фреймов. Некоторым браузерам (особенно Mozilla) требуется id, чтобы сделать iframe доступным как объект. Назначая оба атрибута iframe, вы сохраняете свои параметры открытыми. Но name гораздо важнее, чем id.
Доступ
Либо вы обращаетесь к iframe как к объекту и меняете его src, либо вы обращаетесь к iframe как к фрейму и меняете его location.href.
document.getElementById ('iframe_id'). src = 'newpage.html'; кадры ['iframe_name']. location.href = 'newpage.html'; Синтаксис кадра немного предпочтительнее, потому что его поддерживает Opera 6, но не синтаксис объекта.
Доступ к iframe
Поэтому для полноценной работы с несколькими браузерами вы должны дать iframe имя и использовать
frames['testiframe'].location.href
синтаксис. Насколько я знаю, это всегда работает.
Доступ к документу
Получить доступ к документу внутри iframe довольно просто, если вы используете атрибут name. Чтобы подсчитать количество ссылок в документе в iframe, выполните
frames['testiframe'].document.links.length.
Созданные фреймы
Однако, когда вы генерируете iframe через W3C DOM, iframe не сразу вводится в массив frames, и синтаксис frames['testiframe'].location.href не будет работать сразу. Браузеру нужно немного времени, прежде чем iframe появится в массиве, время, в течение которого скрипт не может работать.
Синтаксис document.getElementById('testiframe').src отлично работает при любых обстоятельствах.
Атрибут ссылки target также не работает с сгенерированными iframe, за исключением Opera, хотя я дал своему сгенерированному iframe как name, так и id.
Отсутствие поддержки target означает, что вы должны использовать JavaScript для изменения содержимого сгенерированного iframe, но поскольку вам в любом случае нужен JavaScript для его генерации в первую очередь, я не вижу в этом большой проблемы.
Размер текста в окнах iframe
Любопытная ошибка только в Explorer 6:
Когда вы изменяете размер текста через меню «Вид», размеры текста в окнах iframe изменяются правильно. Однако этот браузер не изменяет разрывы строк в исходном тексте, так что часть текста может стать невидимой или могут возникать разрывы строк, когда в строке все еще может содержаться другое слово.
Эта ссылка не работает.
И что еще хуже, я нигде не могу найти соответствующую страницу в quirksmode.
FWIW - web.archive.org/web/20080225210716/http://www.quirksmode.org / js /…
Предположим, что идентификатор вашего iFrame - targetFrame, а функция, которую вы хотите вызвать, - targetFunction():
document.getElementById('targetFrame').contentWindow.targetFunction();
Вы также можете получить доступ к фрейму, используя window.frames вместо document.getElementById.
// this option does not work in most of latest versions of chrome and Firefox
window.frames[0].frameElement.contentWindow.targetFunction();
работает в FF 7, Chrome 12, IE 8/9 и Safari (не уверен в этой версии)
Это решение не работает для моего гаджета, вот мой код document.getElementById('remote_iframe_0').contentWindow.my.create_element_gadget('verify_user');" remote_iframe_0 создается программно сервером apache shindig, но window.parent.document.getElementById('remote_iframe_0').contentWindow.my.create_element_gadget('verify_user');" работает
это не работает, если функция в iframe определена как функция jQuery.
@Dirty Henry, что вы имеете в виду под "функцией jQuery"? jQuery - это библиотека JavaScript.
@JoelAnair Вероятно, он имел в виду объект jQuery. то есть $('iframe'). Вам нужно будет сделать $('iframe')[0] или что-то еще, чтобы получить конкретный элемент DOM, который вы хотите.
@GiovanniBitliner Не соответствует действительности. Я только что протестировал его в Chrome v31, и он отлично работает.
@Mark Amery, я получаю SecurityError: Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame., когда пробую его в Chrome 36.0.1985.125.
@JellicleCat Это потому, что родительская страница и iframe имеют разные хосты, что делает его фреймом с перекрестным происхождением, как сообщает вам сообщение. Если протокол, домен и порт родительской страницы и iframe совпадают, все будет работать нормально.
Я добавил пример того, как использовать упомянутый метод window.frames.
Как это сделать с междоменными фреймами iframe?
@JoelAnair Я пытаюсь получить положение прокрутки страницы iFrame (то же происхождение). Как мне вызвать функцию onscroll? У меня есть в теге iframe onscroll=targetFunction(), но он не вызывает функцию.
Теперь существует стандартизированный и безопасный способ сделать это, включая обмен сообщениями между доменами. См. developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_A PI /…
Просто примечание, если вы работаете с JQuery и пытаетесь этого добиться, тогда вам нужно убедиться, что вы не смешиваете ванильные вызовы JS и JQuery. Я нашел ответ, который поможет мне в этом здесь stackoverflow.com/a/32322583/299014
где вы добавляете эти строки? index.html? (если да, то где там?)
IFRAME должен быть в коллекции frames[]. Используйте что-нибудь вроде
frames['iframeid'].method();
В этом ответе, безусловно, может быть дополнительная информация, так как определенно есть некоторые другие соображения. Во-первых, я предполагаю, что разработчику необходимо сделать method свойством объекта window iframe.
В IFRAME сделайте вашу функцию общедоступной для объекта окна:
window.myFunction = function(args) {
doStuff();
}
Для доступа с родительской страницы используйте это:
var iframe = document.getElementById("iframeId");
iframe.contentWindow.myFunction(args);
Отличный ответ. Не уверен в условности здесь. У меня есть дополнительный вопрос. Если я начну новый Вопрос, я сделаю это. У меня одна проблема. Iframe моей страницы заполняется динамически. Он содержит кнопку, событие onclick() которой просто вызывает window.print(). Это идеально печатает содержаниеiframe. Но когда общедоступная функция страницы iframe вызывает window.print() и если родительская страница вызывает общедоступную функцию, печатается содержимое родительской страницы. Как мне это закодировать, чтобы вызов window.print() в публичной функции вел себя так же, как в событии onclick?
@Karl Ты не хочешь звонить onclick. Вы хотите вызвать в iframe.contentWindow.print().
К сожалению, это не работает. Может мне стоит начать новый вопрос и задокументировать свой код? В любом случае печатается и содержимое родительской страницы. document.getElementById('myFrame').contentWindow.print();' and the pubic function printContent () `(не обработчик события oncick), который вызывает window.print(), был вызван следующим образом: document.getElementById('myFrame').contentWindow.printContent();
@Karl - Да, тогда лучше начать новый вопрос. Если только родительское окно не находится в другом домене, чем iframe. Тогда ничего из того, что ты попробуешь, никогда не сработает.
То, что я здесь сообщил, похоже, является проблемой IE (тестирование в IE8). В текущей версии Chrome проблем нет. Однако еще не тестировали другие браузеры. Для тех, кто заинтересован, см. Этот jsFiddle (я думаю, что это хороший пример динамической загрузки iframe и вызова публичной функции из родителя).
и тем, кто заинтересован, я задал следующий вопрос здесь: Вызов javascript в iframe с родительской страницы, проблема с IE
У меня возникли проблемы с вызовом внутренней функции из родительского кадра в бета-версии FF23, использование window.functionName в объявлении (в отличие от var functionName) разрешило ошибку разрешения, с которой я столкнулся, несмотря на явное использование document.domain во всех задействованных кадрах. +1
лучший из тех, что я нашел для общения с родителями, я действительно не хочу безопасности, я просто хочу общаться, спасибо, чувак
Это не очень хорошее решение, по крайней мере, у меня оно не сработало, я получал ошибки CORS. В этом случае попробуйте использовать что-то вроде этого (скопировано из ответа ниже): document.getElementById('my_iframe').contentWindow.postMessage('foo','*');
@Nobody Ничто в моем ответе не говорит о том, что это будет работать во всех доменах. Даже вопрос ничего не говорит о пересечении границ доменов. Если вы получаете ошибки CORS, ваша проблема - совершенно другой.
Здесь есть некоторые особенности, о которых следует знать.
HTMLIFrameElement.contentWindow, вероятно, более простой способ, но это не совсем стандартное свойство, и некоторые браузеры не поддерживают его, в основном старые. Это связано с тем, что в стандарте HTML DOM Level 1 ничего не говорится об объекте window.
Вы также можете попробовать HTMLIFrameElement.contentDocument.defaultView, который позволяют несколько старых браузеров, но не IE. Тем не менее, стандарт прямо не говорит о том, что вы получаете объект window обратно по той же причине, что и (1), но вы можете выбрать здесь несколько дополнительных версий браузера, если вам интересно.
window.frames['name'], возвращающий окно, является самым старым и, следовательно, самым надежным интерфейсом. Но затем вам нужно использовать атрибут name = "...", чтобы иметь возможность получить кадр по имени, что немного некрасиво / устарел / transitional. (id = "..." был бы лучше, но IE это не нравится.)
window.frames[number] также очень надежен, но знание правильного индекса - это хитрость. Вы можете уйти с этим, например. если вы знаете, что у вас есть только один iframe на странице.
Вполне возможно, что дочерний iframe еще не загружен или что-то еще пошло не так, что сделало его недоступным. Возможно, вам будет проще изменить поток обмена данными: то есть, чтобы дочерний iframe уведомил свой сценарий window.parent, когда он завершил загрузку и готов к обратному вызову. Передав один из своих собственных объектов (например, функцию обратного вызова) родительскому скрипту, этот родитель может напрямую взаимодействовать со скриптом в iframe, не беспокоясь о том, с каким HTMLIFrameElement он связан.
Отличный материал! Особенно ваше предложение 5. оказалось чрезвычайно ценным. Это избавило меня от многих головных болей при попытке доступа к функциям iFrame из родительского элемента в Chrome. Передача объекта функции из iFrame заставила его работать как шарм в Chrome, FF и даже IE с 9 до 7, а также упростила проверку, загружена ли уже функция. Спасибо!
Номер 3 работает, но лучше, если вы сделаете это так, как @le dorfier написал в своем комментарии. Обратите внимание на деталь methode().
Также обратите внимание, что из-за ограничений безопасности в современных браузерах (проверенных FF29 и Chrome34) очень важно, где вы размещаете вызов функции. Просто вызвать функцию из тега скрипта или $ (document) .ready () не получится. Вместо этого поместите вызов в тег onload тела или в привязку <a href = "javascript:doit();"> сделайте это </a>, как предложено в другом месте (см. stackoverflow.com/questions/921387/…). Передача вызова функции скрипту в качестве обратного вызова также обычно работает.
@chovy: Нет, см. пояснение в ответе Вивека по этому поводу.
$("#myframe").load(function() {
alert("loaded");
});
Для записи: сегодня я столкнулся с той же проблемой, но на этот раз страница была встроена в объект, а не в iframe (поскольку это был документ XHTML 1.1). Вот как это работает с объектами:
document
.getElementById('targetFrame')
.contentDocument
.defaultView
.targetFunction();
(извините за уродливые разрывы строк, не влезло в одну строку)
Вызов родительской JS-функции из iframe возможен, но только тогда, когда и родительская функция, и страница, загруженная в iframe, находятся в одном домене, то есть abc.com, и оба используют один и тот же протокол, то есть оба находятся либо на http://, либо на https://.
Вызов не будет выполнен в следующих случаях:
Любой способ обхода этого ограничения был бы крайне небезопасным.
Например, представьте, что я зарегистрировал домен superwinningcontest.com и разослал ссылки на электронные письма людей. Когда они загрузили главную страницу, я мог спрятать там несколько iframe и прочитать их фид в Facebook, проверить недавние транзакции Amazon или PayPal или - если они использовали службу, не обеспечивающую достаточной безопасности - перевести деньги со своих Счета. Вот почему JavaScript ограничивается одним доменом и одним протоколом.
Обходной путь - использовать красивый и опасный en.wikipedia.org/wiki/Cross-document_messaging
Кто-нибудь знает, приведет ли это к сбою в другом субдомене? Мне трудно отладить проблему, которая, как я считаю, связана с этим - iframe вызывает функцию родительского окна, но вызова не происходит.
Обратите внимание, это также не сработает для разных номеров портов. т.е. abc.com:80! = abc.com:8080
То же самое, но немного проще - Как обновить родительскую страницу со страницы в iframe. Просто вызовите функцию родительской страницы, чтобы вызвать функцию javascript для перезагрузки страницы:
window.location.reload();
Или сделайте это прямо со страницы в iframe:
window.parent.location.reload();
Оба работают.
Продолжая ответ JoelAnair's:
Для большей надежности используйте следующее:
var el = document.getElementById('targetFrame');
if (el.contentWindow)
{
el.contentWindow.targetFunction();
}
else if (el.contentDocument)
{
el.contentDocument.targetFunction();
}
Работал как шарм :)
Если цель iFrame и содержащий документ находятся в другом домене, ранее опубликованные методы могут не работать, но есть решение:
Например, если документ A содержит элемент iframe, который содержит документ B, а сценарий в документе A вызывает postMessage () для объекта Window документа B, то событие сообщения будет запущено для этого объекта, помеченного как происходящее из Window of документ A. Сценарий в документе A может выглядеть так:
var o = document.getElementsByTagName('iframe')[0];
o.contentWindow.postMessage('Hello world', 'http://b.example.org/');
Чтобы зарегистрировать обработчик событий для входящих событий, сценарий должен использовать addEventListener () (или аналогичные механизмы). Например, сценарий в документе B может выглядеть так:
window.addEventListener('message', receiver, false);
function receiver(e) {
if (e.origin == 'http://example.com') {
if (e.data == 'Hello world') {
e.source.postMessage('Hello', e.origin);
} else {
alert(e.data);
}
}
}
Этот сценарий сначала проверяет, является ли домен ожидаемым доменом, а затем просматривает сообщение, которое он либо отображает пользователю, либо отвечает, отправляя сообщение обратно в документ, который отправил сообщение в первую очередь.
через http://dev.w3.org/html5/postmsg/#web-messaging
это здорово ... попробовав ответы выше, я наконец получил ваш ответ, спасибо!
Если вы хотите вызвать функцию JavaScript в родительском элементе из iframe, созданного другой функцией, например, shadowbox или lightbox.
Вы должны попытаться использовать объект window и вызвать родительскую функцию:
window.parent.targetFunction();
Я считаю, что OP пытается пойти в другом направлении
Попробуй просто parent.myfunction()
@Saeid OP хочет вызвать функцию в iframe из родительского окна, а не наоборот.
После ответа Nitin Bansal
и для еще большей надежности:
function getIframeWindow(iframe_object) {
var doc;
if (iframe_object.contentWindow) {
return iframe_object.contentWindow;
}
if (iframe_object.window) {
return iframe_object.window;
}
if (!doc && iframe_object.contentDocument) {
doc = iframe_object.contentDocument;
}
if (!doc && iframe_object.document) {
doc = iframe_object.document;
}
if (doc && doc.defaultView) {
return doc.defaultView;
}
if (doc && doc.parentWindow) {
return doc.parentWindow;
}
return undefined;
}
и
...
var el = document.getElementById('targetFrame');
var frame_win = getIframeWindow(el);
if (frame_win) {
frame_win.targetFunction();
...
}
...
Я нашел довольно изящное решение.
Как вы сказали, довольно легко выполнить код, расположенный в родительском документе. И это основа моего кода, как раз наоборот.
Когда мой iframe загружается, я вызываю функцию, расположенную в родительском документе, передавая в качестве аргумента ссылку на локальную функцию, расположенную в документе iframe. Родительский документ теперь имеет прямой доступ к функции iframe через эту ссылку.
Пример:
О родителе:
function tunnel(fn) {
fn();
}
В iframe:
var myFunction = function() {
alert("This work!");
}
parent.tunnel(myFunction);
Когда iframe загружается, он вызывает parent.tunnel (YourFunctionReference), который выполнит функцию, полученную в параметре.
Это просто, без необходимости иметь дело со всеми нестандартными методами из различных браузеров.
Привет, можете ли вы подтвердить это «Все просто, без необходимости иметь дело со всеми нестандартными методами из различных браузеров»?
Я использую этот метод в различных проектах, кажется, он работает очень хорошо. Я лично не тестировал все браузеры, которые есть в обращении, но и сообщений об ошибках у меня не было.
Работает как шарм, IE 11, Chrome ~ 50.
Думаю, это не междоменный .. Не так ли?
@TusharShukla К сожалению, нет.
Используйте следующее, чтобы вызвать функцию фрейма на родительской странице
parent.document.getElementById('frameid').contentWindow.somefunction()
Некоторые из этих ответов не затрагивают проблему CORS или не делают очевидным, где вы размещаете фрагменты кода, чтобы сделать общение возможным.
Вот конкретный пример. Скажем, я хочу нажать кнопку на родительской странице и сделать что-то внутри iframe. Вот как бы я это сделал.
parent_frame.html
<button id='parent_page_button' onclick='call_button_inside_frame()'></button>
function call_button_inside_frame() {
document.getElementById('my_iframe').contentWindow.postMessage('foo','*');
}
iframe_page.html
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
if (event) {
click_button_inside_frame();
}
}
function click_button_inside_frame() {
document.getElementById('frame_button').click();
}
Чтобы пойти в другом направлении (нажмите кнопку внутри iframe, чтобы вызвать метод вне iframe), просто переключитесь, где находится фрагмент кода, и измените это:
document.getElementById('my_iframe').contentWindow.postMessage('foo','*');
к этому:
window.parent.postMessage('foo','*')
Наконец-то хорошее решение, спасибо!
Ваша заметка о parent.fuctioName () решила мою проблему с вызовом функции в родительском html iframe. Спасибо!