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

282

Я хочу вызвать функцию родительского окна JavaScript из iframe.

<script>
    function abc()
    {
        alert("sss");
    }
</script>

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>
Арджун Сингх
источник
1
Я не смогу ничего показать прямо сейчас (2016), я не знаю, поддержит ли более старая беседка какую-либо
Weijing Jay Lin

Ответы:

438
<a onclick="parent.abc();" href="#" >Call Me </a>

Смотрите window.parent

Возвращает ссылку на родителя текущего окна или подкадра.

Если у окна нет родителя, его родительское свойство является ссылкой на себя.

Когда окно загружено в <iframe>, <object>или <frame>его родитель окно с элементом вложения в окне.

Рахул
источник
17
Всегда учитывайте, что родительский документ и документ iframe должны совпадать по протоколу и имени домена. Если этого не произойдет, вы получите ошибку безопасности, так как не разрешено использование междоменных сценариев.
a4bike
Мне просто интересно, какой из этих двух alertбудет вызван; родительская alertфункция или функция iframe alert, в случае, если parent.abc();вызывается на iframe?
Прахар Мишра
@PrakharMishra Не смущайтесь. родитель означает родитель.
Саху V Кумар
3
@ a4bike для таких сценариев window.postMessage()(или window.parent.postMessage()) существует. Проверьте ответ @Andrii
Fr0zenFyr
81

Недавно мне пришлось выяснить, почему это тоже не сработало.

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

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="parent.abc();" href="#">Click Me</a>
    </iframe>
</body>

Надеюсь, это поможет любому, кто снова столкнется с этой проблемой.

Эш Кларк
источник
1
Ни один из методов, упомянутых в этом посте, не работает на Chrome. Какие-нибудь решения для этого?
Кумар Куш
3
Если я правильно помню, я не смог бы заставить это работать так, как ожидалось, если бы у iframe был домен, отличный от родительского. Извините, это не решение, но может объяснить, почему оно не работает.
Эш Кларк
1
Да. Я знаю, что это из-за разных доменов, но нет ли способа обойти это?
Кумар Куш
1
Я только что опубликовал, что может быть решение вашей проблемы. Посмотрите на другой ответ.
Эш Кларк
1
Согласно тем же правилам определения политики происхождения (см .: en.wikipedia.org/wiki/… ), поддоменами считается имя хоста, отличное от поддоменов домена. Если вы этого еще не сделали, вы можете попробовать установить document.domain в поддомен?
Эш Кларк
73

Window.postMessage ()

Этот метод позволяет безопасно cross-originобщаться.

И если у вас есть доступ к коду родительской страницы, тогда любой родительский метод может быть вызван, а любые данные могут быть переданы напрямую Iframe. Вот небольшой пример:

Родительская страница:

if (window.addEventListener) {
    window.addEventListener("message", onMessage, false);        
} 
else if (window.attachEvent) {
    window.attachEvent("onmessage", onMessage, false);
}

function onMessage(event) {
    // Check sender origin to be trusted
    if (event.origin !== "http://example.com") return;

    var data = event.data;

    if (typeof(window[data.func]) == "function") {
        window[data.func].call(null, data.message);
    }
}

// Function to be called from iframe
function parentFunc(message) {
    alert(message);
}

Код iframe:

window.parent.postMessage({
    'func': 'parentFunc',
    'message': 'Message text from iframe.'
}, "*");
// Use target origin instead of *

ОБНОВЛЕНИЕ:

Примечание по безопасности:

Всегда указывайте конкретный targetOrigin, NOT *, если вы знаете, где должен находиться документ другого окна. Неспособность указать конкретную цель раскрывает данные, которые вы отправляете на любой заинтересованный вредоносный сайт (комментарий ZalemCitizen ).

Ссылки:

Андрей Вербицкий
источник
1
Я предпочитаю использовать это по сравнению с другими. Тем более, что имеет смысл использовать iframes в документах с перекрестным происхождением (хотя программисты используют iframes чаще, чем нет) и учитывая широкую поддержку этой функции в браузерах.
Fr0zenFyr
1
Спасибо! Мне всегда приходится тратить час или больше, возвращаясь и изучая, как вести обмен сообщениями на более сложных, подробных примерах. Это сработало за 60 секунд. Спасибо за пример, который является кратким и по существу.
RandallTo
2
Стоит поднять это (из веб-документов MDN ): всегда указывайте конкретный targetOrigin, а не *, если вы знаете, где должен находиться документ другого окна. Если не
указать
20

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

Недавно эта проблема снова возникла для доступа к родительскому элементу из iframe, ссылающегося на поддомен, и существующие исправления не работали.

На этот раз ответом было изменить то, что document.domain родительской страницы и iframe были одинаковыми. Это обманет те же проверки политики происхождения, что они будут сосуществовать в одном и том же домене (субдомены считаются другим хостом и не пройдут ту же проверку политики происхождения).

Вставьте следующее в <head>страницу в iframe, чтобы соответствовать родительскому домену (с учетом вашего типа документа).

<script>
    document.domain = "mydomain.com";
</script>

Обратите внимание, что это приведет к ошибке при разработке localhost, поэтому используйте проверку, подобную следующей, чтобы избежать ошибки:

if (!window.location.href.match(/localhost/gi)) {
    document.domain = "mydomain.com";
} 
Эш Кларк
источник
а как насчет тестирования этого в localhost? любой обходной путь для этого?
Умеш Авастхи
Смотрите: «Обратите внимание, что это приведет к ошибке при разработке localhost, поэтому используйте проверку, подобную следующей, чтобы избежать ошибки»
Ash Clarke
2
Стоит отметить, что (по крайней мере, в Google Chrome) родительский и дочерний элементы ДОЛЖНЫ УСТАНОВИТЬ document.domain, даже если один из них уже «правильный»! Пример: Parent - example.comiframe abc.example.com, то и родитель, и iframe должны вызыватьdocument.domain = "example.com"
KillerX
Да, это правильно, я сделал здесь опечатку: «страница в iframe будет такой же». должно быть «страница и iframe должны быть одинаковыми». ..... Спасибо!
Эш Кларк
для if () почему бы вам просто не использовать if (document.domain! = "mydomain.com"? Кроме того, я запутался, идет ли <script> в родительское окно или iFrame? Кроме того, установка document.domain в iFrame создает «Не удалось установить свойство« domain »для« Document »:« localhost »не является суффиксом« sc-localhost ».
user2568374
18

Ты можешь использовать

window.top

смотрите следующее.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="window.top.abc();" href="#">Click Me</a>
    </iframe>
</body>
Виноткумар Арпутарадж
источник
При попытке вызвать parent.custom_function (); из iframe не работает, вы можете найти window.top.custom_function (); буду работать. У меня работает по какой-то странной причине. Мои javascripts в родительском окне все встроены в нижний колонтитул, я где-то читал, что включение javascript-файлов в нижний колонтитул вызывает проблему parent.custom_function () не работает.
Фризо Хорстман
@Vinothkumar, один вопрос, пожалуйста, в чем разница между вызовом "window.top.abc ()" и вызовом только "abc ()", заранее спасибо =)
Зилев А.В.
@Zilev av. Весь смысл этой темы - вызов функции в родительском документе из дочернего iframe. В этом разница. Вызов abc()будет работать, только если он function abc()был объявлен в iframe, а не на родительской странице. window.top.abc()вырывается из iframe в родительский документ.
Шон Кендл
3

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

Девон
источник
2

Решение Ash Clarke для поддоменов прекрасно работает, но учтите, что вам необходимо включить document.domain = "mydomain.com"; как в заголовке страницы iframe, так и в заголовке родительской страницы, как указано в ссылке, одни и те же проверки политики происхождения

Важное расширение той же политики происхождения, реализованной для доступа к DOM JavaScript (но не для большинства других разновидностей проверок одного и того же происхождения), заключается в том, что два сайта, совместно использующие общий домен верхнего уровня, могут предпочесть связь, несмотря на отказ «одного хоста» проверьте путем взаимной установки соответствующего свойства DOM document.domain к тому же квалифицированному правому фрагменту их текущего имени хоста. Например, если http://en.example.com/ и http://fr.example.com/ оба установят document.domain в «example.com», они будут с этого момента считаться одним источником для цель манипулирования DOM.

Frato
источник
Да, это правильно, я сделал здесь опечатку: «страница в iframe будет такой же». должно быть «страница и iframe должны быть одинаковыми». ..... Спасибо!
Эш Кларк
как насчет запуска файлов на локальном компьютере? какова стоимость document.domain?
Raptor
Это будет localhostили IP-адрес машины (обычно 127.0.0.1), в зависимости от того, что находится в адресной строке URL.
Эш Кларк
2

parent.abc () будет работать только на одном домене в целях безопасности. Я попробовал этот обходной путь, и мой работал отлично.

<head>
    <script>
    function abc() {
        alert("sss");
    }

    // window of the iframe
    var innerWindow = document.getElementById('myFrame').contentWindow;
    innerWindow.abc= abc;

    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="abc();" href="#">Click Me</a>
    </iframe>
</body>

Надеюсь это поможет. :)

Seph Remotigue
источник
Это также действительно любое использование документа iframe, добавляя значительные сложности, если вам нужно обратиться к элементам управления в родительской форме.
Пол
1

С Firefox и Chrome вы можете использовать:

<a href="whatever" target="_parent" onclick="myfunction()">

Если myfunction присутствует и в iframe, и в parent, будет вызвана родительская функция.

снежинка
источник
это не работает Вот мое демо: dotku.github.io/tech/html/iframe/iframe_function_container.html
Weijing Jay Lin
Как утверждает Эш Кларк, javascript, который вы хотите вызвать от ребенка, должен находиться в голове родителя.
снежинка
Принятый ответ не нуждается в сценарии, чтобы быть в голове. Я не проверял, больше не нужно ли этому решению сценарий быть в голове или нет.
Гай Шалнат
0

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

Чтобы избежать этого, используйте шаблон модуля. В родительском окне:

var myThing = {
    var i = 0;
    myFunction : function () {
        // do something
    }
};

var newThing = Object.create(myThing);

Затем в iframe:

function myIframeFunction () {
    parent.myThing.myFunction();
    alert(parent.myThing.i);
};

Это похоже на паттерны, описанные в главе «Наследование» оригинального текста Крокфорда «Javascript: The Good Parts». Вы также можете узнать больше на странице w3 о лучших практиках Javascript. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

Уильям Дж. Литтлфилд
источник