从父页面调用iframe中的JavaScript代码

基本上,我有一个iframe嵌入在一个页面中,iframe有一些JavaScript例程,我需要从父页面调用。

现在,相反的情况非常简单,因为您只需要调用parent.functionName(),但不幸的是,我需要的恰恰相反。

请注意,我的问题不是更改iframe的源URL,而是调用iframe中定义的函数。

567596 次浏览

quirkmode有一个关于这个的帖子

由于这个页面现在已经坏了,只能通过archive.org访问,我在这里复制了它:

IFrames

在本页中,我简要介绍了如何从iframe所在的页面访问它们。毫无疑问,这里有一些浏览器方面的考虑。

iframe是一种内联框架,这种框架虽然包含一个具有自己URL的完全独立的页面,但仍然放置在另一个HTML页面中。这为网页设计提供了很好的可能性。问题是如何访问iframe,例如在其中加载一个新页面。本页解释了如何做到这一点。

框架还是物体?

最基本的问题是iframe是被视为一个框架还是一个对象。

  • 正如在框架介绍页面上所解释的,如果你使用框架,浏览器会为你创建一个框架层次结构(top.frames[1].frames[2]之类的)。iframe是否符合这个框架层次结构?
  • 或者浏览器将iframe视为另一个对象,一个恰好具有src属性的对象?在这种情况下,我们必须使用标准的DOM调用(如document.getElementById('theiframe'))来访问它。 一般浏览器允许'real'(硬编码)iframe的两种视图,但生成的iframe不能作为帧访问

名称属性

最重要的规则是给您创建的任何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

< p > . getelementbyid(“iframe_id”)。SRC = 'newpage.html'; 帧的iframe_name .location。Href = 'newpage.html'; 帧语法稍好一些,因为Opera 6支持它,但不支持对象语法

访问iframe

因此,为了获得完整的跨浏览器体验,您应该为iframe命名并使用

frames['testiframe'].location.href

语法。据我所知,这总是管用的。

访问文档

如果您使用name属性,那么访问iframe内的文档非常简单。若要在iframe中计算文档中的链接数量,请执行 # EYZ1。< / p >

生成的iframes

当您通过W3C DOM生成iframe时,iframe不会立即输入到frames数组中,并且frames['testiframe'].location.href语法不会立即工作。在iframe出现在数组中之前,浏览器需要一些时间,在这段时间内不可能运行任何脚本。

document.getElementById('testiframe').src语法在所有情况下都可以正常工作。

链接的target属性也不能用于生成的iframe,除了在Opera中,尽管我给了我生成的iframe一个name和一个id

缺乏target支持意味着您必须使用JavaScript来更改生成的iframe的内容,但由于您首先需要JavaScript来生成它,所以我不认为这是一个大问题。

iframe中的文本大小

Explorer 6特有的奇怪bug:

当您通过“视图”菜单更改文本大小时,iframe中的文本大小将正确更改。但是,此浏览器不会更改原始文本中的换行符,因此部分文本可能变得不可见,或者可能在行中仍然包含另一个单词时出现换行符。

假设你的iFrame的id是“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();

IFRAME应该在frames[]集合中。使用像这样的东西

frames['iframeid'].method();

在IFRAME中,让你的函数对窗口对象是公共的:

window.myFunction = function(args) {
doStuff();
}

从父页面访问,使用这个:

var iframe = document.getElementById("iframeId");
iframe.contentWindow.myFunction(args);

这里有一些需要注意的怪癖。

  1. HTMLIFrameElement.contentWindow可能是更简单的方法,但它不是一个标准属性,一些浏览器不支持它,大多数是旧的浏览器。这是因为DOM Level 1 HTML标准对window对象没有任何说明。

  2. 您还可以尝试HTMLIFrameElement.contentDocument.defaultView,这是一些较老的浏览器允许的,但IE不允许。即便如此,标准并没有明确地说您可以返回window对象,原因与(1)相同,但是如果您愿意,您可以在这里获得一些额外的浏览器版本。

  3. 返回窗口的window.frames['name']是最古老的,因此也是最可靠的接口。但是你必须使用name="..."属性才能按名称获取帧,这有点难看/deprecated/transitional。(id="..."会更好,但IE不喜欢。)

  4. window.frames[number]也非常可靠,但关键是要知道正确的索引。你可以侥幸逃脱。如果你知道页面上只有一个iframe。

  5. 完全有可能子iframe还没有加载,或者有其他错误使它无法访问。您可能会发现反转通信流更容易:也就是说,让子iframe在完成加载并准备好被回调时通知它的window.parent脚本。通过传递它自己的一个对象(例如。一个回调函数)到父脚本,父脚本可以直接与iframe中的脚本通信,而不必担心它与什么HTMLIFrameElement相关联。

       $("#myframe").load(function() {
alert("loaded");
});

为了记录,我今天遇到了同样的问题,但这次页面嵌入在对象中,而不是iframe(因为它是XHTML 1.1文档)。下面是它如何处理对象:

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

(对不起,很难看的换行,不适合单行)

iframe调用父JS函数是可能的,但只有当父JS函数和加载在iframe中的页面都来自同一个域,即example.com,并且两者都使用相同的协议,即都在http://https://上。

在以下情况下调用将失败:

  1. 父页面和iframe页面来自不同的域
  2. 他们使用不同的协议,一个在http://,另一个在https://.

任何解决这个限制的方法都是非常不安全的。

例如,假设我注册了域名superwinningcontest.example,并向人们的电子邮件发送链接。当他们加载主页时,我可以在其中隐藏一些# eyz1,并阅读他们的Facebook动态,查看最近的亚马逊或PayPal交易,或者(如果他们使用的服务没有实现足够的安全性)从他们的账户中转钱。这就是JavaScript仅限于同一域和同一协议的原因。

同样的事情,但更简单的方法是如何从iframe内的页面刷新父页。 只需调用父页面的函数来调用javascript函数来重新加载页面:

window.location.reload();

或者直接从iframe中的页面执行此操作:

window.parent.location.reload();

这两个工作。

继续用JoelAnair的回答:

为了获得更强的健壮性,使用如下方法:

var el = document.getElementById('targetFrame');


if(el.contentWindow)
{
el.contentWindow.targetFunction();
}
else if(el.contentDocument)
{
el.contentDocument.targetFunction();
}

像魅力一样工作:)

如果iFrame的目标和包含的文档在不同的域中,之前发布的方法可能不起作用,但有一个解决方案:

例如,如果文档A包含一个包含文档B的iframe元素,并且文档A中的脚本在文档B的Window对象上调用postMessage(),那么消息事件将在该对象上触发,标记为源自文档A的Window。文档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);
}
}
}

该脚本首先检查域是否是预期的域,然后查看消息,它可以将消息显示给用户,也可以通过将消息发送回最初发送消息的文档来进行响应。

通过# EYZ0

如果你想从另一个函数生成的iframe中调用父节点上的JavaScript函数,例如shadowbox或lightbox。

你应该尝试使用window对象并调用父函数:

window.parent.targetFunction();

试试parent.myfunction()

下面是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),它将执行parameter中接收到的函数。

这很简单,不需要处理来自各种浏览器的所有非标准方法。

使用following调用父页中帧的函数

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