Вызов кода JavaScript в iframe с родительской страницы

По сути, у меня есть встроенный в страницу iframe, а в iframe есть несколько JavaScript подпрограмм, которые мне нужно вызывать с родительской страницы.

Теперь все наоборот: вам нужно всего лишь позвонить parent.functionName(), но, к сожалению, мне нужно прямо противоположное этому.

Обратите внимание, что моя проблема не в изменении исходного URL iframe, а в вызове функции, определенной в iframe.

Ответ 1

Предположим, что ваш iFrame id является "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(); 

Ответ 2

Здесь есть некоторые причуды.

  • HTMLIFrameElement.contentWindow, вероятно, является более простым способом, но это не совсем стандартное свойство, и некоторые браузеры его не поддерживают, в основном более старые. Это связано с тем, что стандарт HTML DOM уровня 1 не имеет ничего общего с объектом window.

  • Вы также можете попробовать HTMLIFrameElement.contentDocument.defaultView, который разрешено нескольким более старым браузерам, но IE нет. Тем не менее, стандарт не говорит о том, что вы возвращаете объект window по той же причине, что и (1), но здесь вы можете получить несколько дополнительных версий браузера.

  • window.frames['name'] Возврат окна является самым старым и, следовательно, самым надежным интерфейсом. Но тогда вам нужно использовать атрибут name="...", чтобы иметь возможность получить фрейм по имени, который немного уродливый / устаревший/переходный. (id="..." было бы лучше, но IE это не нравится.)

  • window.frames[number] также очень надежна, но знание правильного индекса - это трюк. Вы можете избежать этого, например. если вы знаете, что на странице есть только один iframe.

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

Ответ 3

Вызов родительской функции JS из iframe возможен, но только тогда, когда и родительский, и страница, загруженные в iframe, принадлежат к одному домену, то есть abc.com, и оба используют один и тот же протокол, то есть оба находятся на http:// или https://.

В нижеуказанных случаях вызов завершится неудачно:

  • Родительская страница и страница iframe из разных доменов.
  • Они используют разные протоколы, один находится на http://, а другой - на https://.

Любое обходное решение этого ограничения было бы крайне неуверенным.

Например, представьте, что я зарегистрировал домен superwinningcontest.com и отправил ссылки на электронные письма пользователей. Когда они загрузили главную страницу, я мог бы скрыть несколько iframe там и прочитать их фид Facebook, проверить последние транзакции Amazon или PayPal, или - если они использовали службу, которая не обеспечивала достаточную безопасность - деньги перевода их счетов. Поэтому JavaScript ограничен однопользовательским и одинаковым протоколом.

Ответ 4

В IFRAME сделайте свою функцию открытой для объекта window:

window.myFunction = function(args) {
   doStuff();
}

Для доступа с родительской страницы используйте следующую команду:

var iframe = document.getElementById("iframeId");
iframe.contentWindow.myFunction(args);

Ответ 5

Если iFrame и содержащий его документ находятся в другом домене, ранее опубликованные методы могут не работать, но есть решение:

Например, если документ A содержит элемент iframe, который содержит документ B, а сценарий в документе A вызывает postMessage() для объекта Window документа B, то для этого объекта будет сгенерировано событие сообщения, помеченное как происходящее из окна документ А. Сценарий в документе А может выглядеть следующим образом:

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

Ответ 6

Только для записи я столкнулся с той же проблемой сегодня, но на этот раз страница была встроена в объект, а не iframe (поскольку это был документ XHTML 1.1). Здесь, как это работает с объектами:

document
  .getElementById('targetFrame')
  .contentDocument
  .defaultView
  .targetFunction();

(извините за уродливые разрывы строк, не вписывается в одну строку)

Ответ 7

В Quirksmode было сообщение об этом.

Поскольку страница теперь разбита и доступна только через archive.org, я воспроизвел ее здесь:

IFrames

На этой странице я даю краткий обзор доступа к iframes со страницы, на которой они находятся. Неудивительно, что есть некоторые соображения браузера.

iframe - это встроенный фрейм, который, хотя и содержит полностью отдельную страницу со своим собственным URL-адресом, тем не менее размещается внутри другой HTML-страницы. Это дает очень хорошие возможности в веб-дизайне. Проблема заключается в доступе к iframe, например, для загрузки в него новой страницы. На этой странице объясняется, как это сделать.

Кадр или объект?

Основной вопрос заключается в том, рассматривается ли iframe как кадр или как объект.

  • Как объяснено на страницах Introduction to frames, если вы используете фреймы, браузер создает для вас иерархию фреймов (top.frames[1].frames[2] и т.д.), Включен ли iframe в эту иерархию кадров?
  • Или браузер видит iframe как еще один объект, объект, который имеет свойство src? В этом случае мы должны использовать стандартный DOM-вызов (например, document.getElementById('theiframe'))). В общем случае браузеры допускают оба представления на "реальные" (жестко запрограммированные) iframes, но сгенерированные фреймы не могут быть доступны в качестве фреймов.

атрибут 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'; frames ['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 в массиве, время, в течение которого не может работать script.

Синтаксис document.getElementById('testiframe').src отлично работает при любых обстоятельствах.

Атрибут target ссылки не работает ни с генерируемыми iframes, кроме Opera, хотя я дал свой сгенерированный iframe как name, так и id.

Отсутствие поддержки target означает, что вы должны использовать JavaScript для изменения содержимого сгенерированного iframe, но так как вам нужен JavaScript в любом случае для его создания в первую очередь, я не вижу в этом такой же проблемы.

Размер текста в iframe

Любопытная ошибка Explorer 6:

При изменении размера текста в меню "Вид" размеры текста в iframe будут правильно изменены. Однако этот браузер не изменяет разрывы строк в исходном тексте, так что часть текста может стать невидимой, или могут произойти разрывы строк, пока строка еще может содержать другое слово.

Ответ 8

IFRAME должен находиться в коллекции frames[]. Используйте что-то вроде

frames['iframeid'].method();

Ответ 9

Я нашел довольно элегантное решение.

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

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

Пример:

У родителя:

function tunnel(fn) {
    fn();
}

В iframe:

var myFunction = function() {
    alert("This work!");
}

parent.tunnel(myFunction);

Когда загружается iframe, он вызывается parent.tunnel(YourFunctionReference), который будет выполнять функцию, полученную в параметре.

Это просто, без необходимости иметь дело со всеми нестандартными методами из разных браузеров.

Ответ 10

Некоторые из этих ответов не затрагивают проблему 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','*')

Ответ 11

Продолжая ответ JoelAnair:

Для большей надежности используйте следующее:

var el = document.getElementById('targetFrame');

if(el.contentWindow)
{
   el.contentWindow.targetFunction();
}
else if(el.contentDocument)
{
   el.contentDocument.targetFunction();
}

Работает как шарм:)

Ответ 12

Folowing 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();
  ...
}
...

Ответ 13

       $("#myframe").load(function() {
            alert("loaded");
        });

Ответ 14

То же самое, но немного проще, будет Как обновить родительскую страницу со страницы в iframe. Просто вызовите функцию родительской страницы, чтобы вызвать функцию javascript, чтобы перезагрузить страницу:

window.location.reload();

Или сделайте это прямо со страницы в iframe:

window.parent.location.reload();

Оба работают.

Ответ 15

Если вы хотите вызвать функцию JavaScript в Parent из iframe, сгенерированного другой функцией ex shadowbox или lightbox.

Вы должны попытаться использовать объект window и вызвать родительскую функцию:

window.parent.targetFunction();

Ответ 16

Попробуйте просто parent.myfunction()

Ответ 17

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

parent.document.getElementById('frameid').contentWindow.somefunction()