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

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

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

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

Ваша заметка о parent.fuctioName () решила мою проблему с вызовом функции в родительском html iframe. Спасибо!

CyberFonic 13.06.2011 05:34

Обратите внимание, что при отладке вы можете делать такие вещи, как window.location.href или parent.location.href, чтобы просмотреть URL-адрес iframe, если вы хотите убедиться, что у вас есть ссылка на iframe, который вы ищете.

AaronLS 21.03.2013 23:57

См. Ответ @le dorfier ... отлично сработал для меня.

ErickBest 05.09.2013 14:55
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
637
3
518 369
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

У Quirksmode был опубликовать на этом.

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

IFrames

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

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

Рамка или объект?

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

  • Как объясняется на страницах Введение в фреймы, если вы используете фреймы, браузер создает для вас иерархию фреймов (top.frames[1].frames[2] и т. д.). Подходит ли iframe в эту иерархию фреймов?
  • Или браузер видит iframe просто как еще один объект, объект, у которого есть свойство src? В этом случае мы должны использовать стандартный Вызов DOM (например, 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 изменяются правильно. Однако этот браузер не изменяет разрывы строк в исходном тексте, так что часть текста может стать невидимой или могут возникать разрывы строк, когда в строке все еще может содержаться другое слово.

Эта ссылка не работает.

zaphod 12.06.2009 02:10

И что еще хуже, я нигде не могу найти соответствующую страницу в quirksmode.

stricjux 31.12.2009 13:23
Ответ принят как подходящий

Предположим, что идентификатор вашего 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 (не уверен в этой версии)

Darcy 02.11.2011 23:38

Это решение не работает для моего гаджета, вот мой код document.getElementById('remote_iframe_0').contentWindow.my.‌​create_element_gadg‌‌​​et('verify_user');" remote_iframe_0 создается программно сервером apache shindig, но window.parent.document.getElementById('remote_iframe_0').con‌​tentWindow.my.create‌​_element_gadg‌​et('v‌​erify_user');" работает

J Bourne 10.01.2012 15:30

это не работает, если функция в iframe определена как функция jQuery.

Dirty Henry 04.02.2013 19:05

@Dirty Henry, что вы имеете в виду под "функцией jQuery"? jQuery - это библиотека JavaScript.

Joel Anair 01.07.2013 17:11

@JoelAnair Вероятно, он имел в виду объект jQuery. то есть $('iframe'). Вам нужно будет сделать $('iframe')[0] или что-то еще, чтобы получить конкретный элемент DOM, который вы хотите.

Oscar Godson 05.07.2013 23:42

@GiovanniBitliner Не соответствует действительности. Я только что протестировал его в Chrome v31, и он отлично работает.

Mark Amery 01.06.2014 16:45

@Mark Amery, я получаю SecurityError: Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame., когда пробую его в Chrome 36.0.1985.125.

JellicleCat 15.10.2014 00:04

@JellicleCat Это потому, что родительская страница и iframe имеют разные хосты, что делает его фреймом с перекрестным происхождением, как сообщает вам сообщение. Если протокол, домен и порт родительской страницы и iframe совпадают, все будет работать нормально.

Mark Amery 15.10.2014 00:38

Я добавил пример того, как использовать упомянутый метод window.frames.

Elijah Lynn 25.02.2015 21:43

Как это сделать с междоменными фреймами iframe?

Tushar Shukla 31.05.2016 12:16

@JoelAnair Я пытаюсь получить положение прокрутки страницы iFrame (то же происхождение). Как мне вызвать функцию onscroll? У меня есть в теге iframe onscroll=targetFunction(), но он не вызывает функцию.

TheRealFakeNews 16.11.2016 21:11

Теперь существует стандартизированный и безопасный способ сделать это, включая обмен сообщениями между доменами. См. developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_A‌ PI /…

boris 04.05.2017 20:19

Просто примечание, если вы работаете с JQuery и пытаетесь этого добиться, тогда вам нужно убедиться, что вы не смешиваете ванильные вызовы JS и JQuery. Я нашел ответ, который поможет мне в этом здесь stackoverflow.com/a/32322583/299014

JRSofty 07.12.2017 11:24

где вы добавляете эти строки? index.html? (если да, то где там?)

likuku 17.02.2021 19:21

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

frames['iframeid'].method();

В этом ответе, безусловно, может быть дополнительная информация, так как определенно есть некоторые другие соображения. Во-первых, я предполагаю, что разработчику необходимо сделать method свойством объекта window iframe.

matty 24.06.2015 08:06

В 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 02.08.2012 00:43

@Karl Ты не хочешь звонить onclick. Вы хотите вызвать в iframe.contentWindow.print().

Tomalak 02.08.2012 01:15

К сожалению, это не работает. Может мне стоит начать новый вопрос и задокументировать свой код? В любом случае печатается и содержимое родительской страницы. document.getElementById('myFrame').contentWindow.print();' and the pubic function printContent () `(не обработчик события oncick), который вызывает window.print(), был вызван следующим образом: document.getElementById('myFrame').contentWindow.printConten‌​t();

Karl 02.08.2012 01:41

@Karl - Да, тогда лучше начать новый вопрос. Если только родительское окно не находится в другом домене, чем iframe. Тогда ничего из того, что ты попробуешь, никогда не сработает.

Tomalak 02.08.2012 06:01

То, что я здесь сообщил, похоже, является проблемой IE (тестирование в IE8). В текущей версии Chrome проблем нет. Однако еще не тестировали другие браузеры. Для тех, кто заинтересован, см. Этот jsFiddle (я думаю, что это хороший пример динамической загрузки iframe и вызова публичной функции из родителя).

Karl 02.08.2012 06:43

и тем, кто заинтересован, я задал следующий вопрос здесь: Вызов javascript в iframe с родительской страницы, проблема с IE

Karl 02.08.2012 16:26

У меня возникли проблемы с вызовом внутренней функции из родительского кадра в бета-версии FF23, использование window.functionName в объявлении (в отличие от var functionName) разрешило ошибку разрешения, с которой я столкнулся, несмотря на явное использование document.domain во всех задействованных кадрах. +1

Chris Baker 18.07.2013 09:57

лучший из тех, что я нашел для общения с родителями, я действительно не хочу безопасности, я просто хочу общаться, спасибо, чувак

ßãlãjî 07.05.2020 17:49

Это не очень хорошее решение, по крайней мере, у меня оно не сработало, я получал ошибки CORS. В этом случае попробуйте использовать что-то вроде этого (скопировано из ответа ниже): document.getElementById('my_iframe').contentWindow.postMessa‌​ge('foo','*');

NobodySomewhere 15.03.2021 18:10

@Nobody Ничто в моем ответе не говорит о том, что это будет работать во всех доменах. Даже вопрос ничего не говорит о пересечении границ доменов. Если вы получаете ошибки CORS, ваша проблема - совершенно другой.

Tomalak 15.03.2021 18:32

Здесь есть некоторые особенности, о которых следует знать.

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

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

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

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

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

Отличный материал! Особенно ваше предложение 5. оказалось чрезвычайно ценным. Это избавило меня от многих головных болей при попытке доступа к функциям iFrame из родительского элемента в Chrome. Передача объекта функции из iFrame заставила его работать как шарм в Chrome, FF и даже IE с 9 до 7, а также упростила проверку, загружена ли уже функция. Спасибо!

Jpsy 24.11.2011 11:10

Номер 3 работает, но лучше, если вы сделаете это так, как @le dorfier написал в своем комментарии. Обратите внимание на деталь methode().

ErickBest 05.09.2013 14:54

Также обратите внимание, что из-за ограничений безопасности в современных браузерах (проверенных FF29 и Chrome34) очень важно, где вы размещаете вызов функции. Просто вызвать функцию из тега скрипта или $ (document) .ready () не получится. Вместо этого поместите вызов в тег onload тела или в привязку <a href = "javascript:doit();"> сделайте это </a>, как предложено в другом месте (см. stackoverflow.com/questions/921387/…). Передача вызова функции скрипту в качестве обратного вызова также обычно работает.

titusn 13.05.2014 14:23

@chovy: Нет, см. пояснение в ответе Вивека по этому поводу.

bobince 28.10.2014 19:40
       $("#myframe").load(function() {
            alert("loaded");
        });

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

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

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

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

Вызов не будет выполнен в следующих случаях:

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

Любой способ обхода этого ограничения был бы крайне небезопасным.

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

Обходной путь - использовать красивый и опасный en.wikipedia.org/wiki/Cross-document_messaging

Laramie 08.01.2013 11:16

Кто-нибудь знает, приведет ли это к сбою в другом субдомене? Мне трудно отладить проблему, которая, как я считаю, связана с этим - iframe вызывает функцию родительского окна, но вызова не происходит.

Jake 20.08.2013 01:55

Обратите внимание, это также не сработает для разных номеров портов. т.е. abc.com:80! = abc.com:8080

prasanthv 01.12.2015 20:17

То же самое, но немного проще - Как обновить родительскую страницу со страницы в 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

easyXDM обеспечивает абстракцию над PostMessage для старых браузеров (включая резервный вариант Flash (LocalConnection) для упрямых динозавров).
JonnyReeves 06.03.2012 13:55

это здорово ... попробовав ответы выше, я наконец получил ваш ответ, спасибо!

vkGunasekaran 05.03.2020 11:33

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

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

window.parent.targetFunction();

Я считаю, что OP пытается пойти в другом направлении

CommandZ 23.01.2020 06:40

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

stackoverflow.com/questions/12960494/…
Milche Patern 27.05.2015 02:25

@Saeid OP хочет вызвать функцию в iframe из родительского окна, а не наоборот.

Jean-François Beauchamp 26.01.2017 21:48

После ответа 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), который выполнит функцию, полученную в параметре.

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

Привет, можете ли вы подтвердить это «Все просто, без необходимости иметь дело со всеми нестандартными методами из различных браузеров»?

Milche Patern 27.05.2015 02:17

Я использую этот метод в различных проектах, кажется, он работает очень хорошо. Я лично не тестировал все браузеры, которые есть в обращении, но и сообщений об ошибках у меня не было.

Julien L 19.06.2015 01:24

Работает как шарм, IE 11, Chrome ~ 50.

Augustas 19.05.2016 09:48

Думаю, это не междоменный .. Не так ли?

Tushar Shukla 31.05.2016 12:22

@TusharShukla К сожалению, нет.

jeff-h 18.06.2018 12:17

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

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','*')

Наконец-то хорошее решение, спасибо!

NobodySomewhere 15.03.2021 18:08

Другие вопросы по теме