从iframe调用父窗口函数


281

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

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

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

1
我现在将无法显示任何内容(2016年),我不知道较旧的凉亭是否会提供任何支撑
Weijing Jay Lin

Answers:


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

参见window.parent

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

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

当在一个被加载的窗口<iframe><object>或者<frame>,它的父是与元件嵌入窗口的窗口。


17
始终考虑到父文档和iframe文档必须通过协议和域名匹配。如果没有发生,那么您将收到一个安全错误,因为它不允许具有跨域脚本。
2015年

M只是想知道alert将调用哪两个?父alert函数或iframe alert函数,以防parent.abc();在iframe上调用?
Prakhar Mishra

@PrakharMishra不要困惑。父母是指父母。
Sahu V Kumar

3
在这种情况下,@ a4bike 存在window.postMessage()(或window.parent.postMessage())。检查@Andrii答案
Fr0zenFyr

81

最近,我不得不找出为什么这也行不通。

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

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

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


1
这篇文章中提到的技术都无法在Chrome上使用。有什么解决办法吗?
Kumar Kush 2012年

3
如果我没记错的话,如果iframe与父级的域不同,那么我将无法正常工作。抱歉,这不是解决方案,但可以解释为什么它不起作用。
Ash Clarke 2012年

1
是。我确实知道这是因为域不同,但是没有办法解决这个问题吗?
库玛·库什

1
我刚刚发布了解决您问题的方法。看看另一个答案。
Ash Clarke 2012年

1
根据相同的来源策略确定规则(请参阅:en.wikipedia.org/wiki/…),子域被视为与域的子域不同的主机名。如果还没有,可以尝试将document.domain设置为子域吗?
Ash Clarke 2014年

72

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
我比其他人更喜欢使用它。特别是因为在跨源文档中使用iframe更有意义(尽管程序员确实经常使用iframe),并且在浏览器中对此功能提供了广泛的支持。
Fr0zenFyr

1
谢谢!我总是要花一个小时或更多的时间来研究如何通过复杂而冗长的示例进行消息传递。这项工作在60秒内完成。感谢一个简洁明了的例子。
RandallTo

2
值得提出这一点(来自MDN Web文档):如果您知道另一个窗口的文档应该位于何处,请始终提供特定的targetOrigin而不是*。没有提供特定的目标,就会透露您发送给任何感兴趣的恶意网站的数据
ZalemCitizen

20

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

最近再次出现此问题,原因是该问题是通过从引用子域的iframe访问父项而导致的,现有的修复程序不起作用。

这次的答案是将父页面和iframe的document.domain修改为相同。这将愚弄相同的原始策略检查以为它们在完全相同的域中共存(子域被视为不同的主机,并且通过相同的原始策略检查失败)。

将以下内容插入到<head>iframe页面的中,以匹配父域(根据您的doctype进行调整)。

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

请注意,这将在localhost开发上引发错误,因此请使用以下检查方法来避免该错误:

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

以及如何在本地主机上测试呢?任何解决方法?
Umesh Awasthi 2012年

请参阅:“请注意,这将在localhost开发上引发错误,因此请使用如下检查以避免该错误”
Ash Clarke

2
值得注意的是,(至少在Google Chrome中)父级和子级都必须设置document.domain,即使其中之一已经“正确”!示例:父级为example.comiframe为abc.example.com,则父级和iframe都必须调用document.domain = "example.com"
KillerX

是的,这是正确的,我在这里做了一个错字:“ iframe中的页面是相同的。” 应为“页面和iframe相同”。..... 谢谢!
Ash Clarke

对于if(),为什么不只使用if(document.domain!=“ mydomain.com”?另外,我很困惑,<script>是放在父窗口还是iFrame中? iFrame中的document.domain会生成“无法在'Document'上设置'domain'属性:'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(); 将工作。出于某种奇怪的原因为我工作。我在父窗口上的javascript全部嵌入到页脚中,我读到某个地方,在页脚中包含javascript文件会导致问题parent.custom_function()无法正常工作。
Friso Horstman

@Vinothkumar,请问一个问题,这是调用“ window.top.abc()”与仅调用“ abc()”之间的区别,预先感谢=)
Zilev 2016年

@Zilev av该线程的全部要点是从子iframe调用父文档中的函数。就是这样。abc()只有在iframe中(而不是在父页面上)function abc()声明时调用才有效。 window.top.abc()脱离iframe进入父文档。
肖恩·肯德尔

3

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


2

Ash Clarke为子域提供的解决方案效果很好,但请注意,您需要包括document.domain =“ mydomain.com”; 如链接中所述,在iframe页面的顶部和父页面的顶部同源策略的检查

对为JavaScript DOM访问实现的同一来源策略(但不是针对其他大多数相同来源检查的大多数实施方式)的一个重要扩展是,共享一个公共顶级域的两个站点可能会选择通信,尽管“同一主机”失败通过相互将它们各自的document.domain DOM属性设置为它们当前主机名的相同的,右侧的右片段来进行检查。例如,如果http://en.example.com/http://fr.example.com/都将document.domain设置为“ example.com”,则从那时起,它们将被认为是相同来源的。 DOM操作的目的。


是的,这是正确的,我在这里做了一个错字:“ iframe中的页面是相同的。” 应为“页面和iframe相同”。..... 谢谢!
Ash Clarke

在本地计算机上运行文件怎么样?的值是document.domain多少?
猛禽

这将是localhost或机器的ip地址(通常是127.0.0.1),具体取决于url地址栏中的内容。
Ash Clarke

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>

希望这可以帮助。:)


实际上,这实际上仅用于iframe文档,如果需要引用父表单上的控件,则会增加大量的复杂性。
保罗

1

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

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

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



如Ash Clarke所述,您要从子iframe调用的javascript必须位于父文件的开头。
雪花

接受的答案不需要脚本在头。我没有测试该解决方案是否也不再需要脚本出现在首位。
Guy Schalnat

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);
};

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.