从 iframe 调用父窗口函数

Posted

技术标签:

【中文标题】从 iframe 调用父窗口函数【英文标题】:Calling a parent window function from an iframe 【发布时间】:2011-01-10 19:24:47 【问题描述】:

我想从 iframe 调用父窗口 javascript 函数。

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

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>

【问题讨论】:

我现在无法显示任何内容(2016 年),我不知道旧版凉亭是否支持任何内容 【参考方案1】:
<a onclick="parent.abc();" href="#" >Call Me </a>

见window.parent

返回对当前窗口或子框架的父级的引用。

如果窗口没有父级,则其父级属性是对自身的引用。

当窗口在&lt;iframe&gt;&lt;object&gt;&lt;frame&gt; 中加载时,其父窗口是包含嵌入窗口的元素的窗口。

【讨论】:

始终考虑父文档和 iframe 文档必须按协议和域名匹配。如果它没有发生,那么您将收到一个安全错误,因为它不允许跨域脚本。 M 只是想知道这两个alerts 中的哪一个会被调用; parent 的 alert 函数或 iframe 的 alert 函数,以防在 iframe 上调用 parent.abc(); @PrakharMishra 不要混淆。父母的意思是父母。 @a4bike 对于这种情况,存在window.postMessage()(或window.parent.postMessage())。检查@Andrii answer【参考方案2】:

我最近不得不找出为什么这也不起作用。

您要从子 iframe 调用的 javascript 需要位于父 iframe 的头部。如果在正文中,则脚本在全局范围内不可用。

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

希望这对再次遇到此问题的人有所帮助。

【讨论】:

本文中提到的所有技术都不适用于 Chrome。有什么解决办法吗? 如果我没记错的话,如果 iframe 的域与父级不同,我无法按预期工作。抱歉,这不是解决方案,但它可以解释为什么它不起作用。 是的。我知道这是因为不同的域,但是没有办法解决这个问题吗? 我刚刚发布了可能是解决您问题的方法。看看另一个答案。 根据同源策略确定规则(参见:en.wikipedia.org/wiki/…),子域被视为与域的子域不同的主机名。如果您还没有,您可以尝试将 document.domain 设置为子域?【参考方案3】:

你可以使用

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 进入父文档。【参考方案4】:

我已将此作为单独的答案发布,因为它与我现有的答案无关。

这个问题最近再次出现,因为从引用子域的 iframe 访问父级并且现有修复不起作用。

这次的答案是将父页面的document.domain和iframe修改为一样。这会使same origin policy checks 误以为它们在完全相同的域上共存(子域被视为不同的主机并且无法通过相同的源策略检查)。

将以下内容插入 iframe 中页面的 &lt;head&gt; 以匹配父域(根据您的文档类型进行调整)。

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

请注意,这会在 localhost 开发时抛出错误,因此请使用如下检查以避免错误:

if (!window.location.href.match(/localhost/gi)) 
    document.domain = "mydomain.com";
 

【讨论】:

那么在 localhost 中测试呢?有什么解决方法吗? 见:“请注意,这会在localhost开发时抛出错误,所以使用如下检查来避免错误” 值得注意的是(至少在谷歌浏览器中)父母和孩子都必须设置 document.domain,即使其中一个已经“正确”!示例:Parent 为example.com iframe 为abc.example.com,则 parent 和 iframe 都必须调用document.domain = "example.com" 是的,没错,我在这里打错了:“iframe 中的页面要相同。”应该是“page和iframe要一样”。 .....谢谢! 对于 if() 为什么不使用 if(document.domain != "mydomain.com" ?另外,我很困惑, 【参考方案5】:

Ash Clarke 为子域提供的解决方案效果很好,但请注意您需要包含 document.domain = "mydomain.com";在iframe页面的头部和父页面的头部,如链接same origin policy checks中所述

为 JavaScript DOM 访问实施的同源策略的一个重要扩展(但对于大多数其他风格的同源检查而言并非如此)是共享一个共同***域的两个站点可能会选择通信,尽管“相同的主机”通过相互将它们各自的 document.domain DOM 属性设置为其当前主机名的相同限定的右侧片段来检查。 例如,如果 http://en.example.com/ 和 http://fr.example.com/ 都将 document.domain 设置为“example.com”,那么出于 DOM 操作的目的,它们将从该点开始被视为同源。

【讨论】:

是的,没错,我在这里打错了:“iframe 中的页面要相同。”应该是“page和iframe要一样”。 .....谢谢! 在本地计算机上运行文件怎么样? document.domain 的值是多少? 它将是localhost 或机器的IP 地址(通常为127.0.0.1),具体取决于url 地址栏中的内容。【参考方案6】:

为需要它的人提供另一个补充。如果他们使用不同的协议,Ash Clarke 的解决方案将不起作用,因此请确保如果您使用 SSL,您的 iframe 也使用 SSL,否则会破坏功能。不过,他的解决方案确实适用于域本身,非常感谢。

【讨论】:

【参考方案7】: 出于安全考虑,

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>

希望这会有所帮助。 :)

【讨论】:

这实际上也只是 iframe 文档的任何用途,如果您需要引用父表单上的控件,则会增加大量复杂性。【参考方案8】:

使用 Firefox 和 Chrome,您可以使用:

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

如果 iframe 和 parent 中都存在 myfunction,则将调用父函数。

【讨论】:

它不起作用。这是我的演示:dotku.github.io/tech/html/iframe/iframe_function_container.html 正如 Ash Clarke 所说,您要从子 iframe 调用的 javascript 需要位于父 iframe 的头部。 接受的答案不需要脚本在头脑中。我没有测试这个解决方案是否也不再需要脚本在头脑中。【参考方案9】:

虽然其中一些解决方案可能有效,但它们都没有遵循最佳做法。许多人分配全局变量,您可能会发现自己调用多个父变量或函数,导致命名空间混乱、易受攻击。

为避免这种情况,请使用模块模式。在父窗口中:

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

var newThing = Object.create(myThing);

然后,在 iframe 中:

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

这类似于 Crockford 的开创性文本“Javascript: The Good Parts”的继承一章中描述的模式。您还可以在 w3 的页面上了解更多关于 Javascript 最佳实践的信息。 https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

【讨论】:

【参考方案10】:

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,而不是 *。未能提供特定目标会泄露您发送到任何感兴趣的恶意网站的数据(ZalemCitizen 评论)。

参考资料:

Cross-document messaging Window.postMessage() Can I Use

【讨论】:

我更喜欢使用这个而不是其他的。尤其是因为在跨源文档上使用 iframe 更有意义(尽管程序员确实经常利用 iframe),并且浏览器上广泛支持此功能。 谢谢!我总是要花一个小时或更长时间回去研究如何用过于复杂、冗长的例子来进行消息传递。这在 60 秒内起作用。感谢您提供简洁明了的示例。 值得一提(来自MDN web docs):如果您知道其他窗口的文档应位于何处,请始终提供特定的 targetOrigin,而不是 *。未能提供特定目标会泄露您发送到任何感兴趣的恶意网站的数据 我喜欢这种做法,答案简洁明了【参考方案11】:

一个插件助手要点,它允许父窗口调用子 iframe 窗口函数,反之亦然,但所有调用都是异步的。

https://gist.github.com/clinuxrulz/77f341832c6025bf10f0b183ee85e072

这也可以跨域工作,但只能调用您从父级导出到 iframe 的函数,并且父窗口只能调用 iframe 导出的函数。

【讨论】:

以上是关于从 iframe 调用父窗口函数的主要内容,如果未能解决你的问题,请参考以下文章

从父文档/窗口调用IFrame Javascript函数

iframe页面调用父窗口JS函数

允许子 iframe 从不同域调用其父窗口上的函数

从父窗口访问 iframe 中的 DOM 附加函数

javascript, iframe, security - 尝试从父窗口访问 js 函数时权限被拒绝

iframe如何传值给父iframe