从 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
返回对当前窗口或子框架的父级的引用。
如果窗口没有父级,则其父级属性是对自身的引用。
当窗口在<iframe>
、<object>
或<frame>
中加载时,其父窗口是包含嵌入窗口的元素的窗口。
【讨论】:
始终考虑父文档和 iframe 文档必须按协议和域名匹配。如果它没有发生,那么您将收到一个安全错误,因为它不允许跨域脚本。 M 只是想知道这两个alert
s 中的哪一个会被调用; 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 中页面的 <head>
以匹配父域(根据您的文档类型进行调整)。
<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 调用父窗口函数的主要内容,如果未能解决你的问题,请参考以下文章