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

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

现在相反是很简单的,因为你只需要调用parent.functionName() ,但不幸的是我需要完全相反的。

请注意,我的问题不是更改iframe的源URL ,而是调用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(); 

有一些怪癖在这里知道。

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

  2. 你也可以尝试HTMLIFrameElement.contentDocument.defaultView ,这是几个较旧的浏览器允许,但IE不。 即便如此,标准并没有明确地说你得到window对象,出于与(1)相同的原因,但是如果你关心的话,你可以在这里select一些额外的浏览器版本。

  3. window.frames['name']返回窗口是最老的,因此也是最可靠的接口。 但是,你必须使用name="..."属性来获得一个名字,这是一个丑陋/ 不赞成 /过渡的框架。 ( id="..."会更好,但IE不喜欢。)

  4. window.frames[number]也是非常可靠的,但知道正确的索引是诀窍。 你可以摆脱这个例如。 如果你知道你只有一个页面上的iframe。

  5. 孩子iframe还没有加载完全可能,或者是其他的错误使得它无法访问。 您可能会发现,更改通信stream程更容易:也就是说,当子结点加载完成并准备好callback时,让子结点的iframe通知其window.parent脚本。 通过将自己的一个对象(例如callback函数)传递给父脚本,该父母就可以直接与iframe中的脚本进行通信,而不必担心与其关联的HTMLIFrameElement。

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

在下面提到的情况下,呼叫将失败:

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

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

例如,假设我注册了域名superwinningcontest.com并发送了链接到人们的电子邮件。 当他们加载主页时,我可以在那里隐藏一些iframe ,阅读他们的Facebook feed,查看最近的亚马逊或PayPal交易,或者如果他们使用的服务没有实现足够的安全性,他们的账户。 这就是为什么JavaScript限于同域和同协议。

在IFRAME中,将你的函数公开给窗口对象:

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

要从父页面访问,请使用以下命令:

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

如果iFrame和包含的文档位于不同的域中,以前发布的方法可能不起作用,但有一个解决scheme:

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

这个脚本首先检查域是预期的域,然后查看它向用户显示的消息,或者通过将消息发回到首先发送消息的文档来响应。

通过http://dev.w3.org/html5/postmsg/#web-messaging

为了logging,我今天遇到了同样的问题,但是这次页面被embedded到一个对象中,而不是一个iframe(因为它是一个XHTML 1.1文档)。 以下是它如何与对象一起工作的:

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

(对于难看的换行符,不适合在一行中)

IFRAME应该在frames[]集合中。 使用类似的东西

 frames['iframeid'].method(); 

我发现相当优雅的解决scheme。

如您所说,执行位于父文档上的代码相当容易。 这就是我的代码的基础,做相反的事情。

当我的iframe加载时,我调用位于父文档上的函数,将作为参数的引用传递给位于iframe文档中的本地函数。 父文档现在可以通过这个引用直接访问iframe的函数。

例:

对于父母:

 function tunnel(fn) { fn(); } 

在iframe上:

 var myFunction = function() { alert("This work!"); } parent.tunnel(myFunction); 

当iframe加载时,它会调用parent.tunnel(YourFunctionReference),它将执行参数中收到的函数。

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

Quirksmode就此发表了一篇文章 。

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

的IFrame

在这个页面上,我简单介绍一下从他们正在访问的页面访问iframe。 毫不奇怪,有一些浏览器的考虑。

一个iframe是一个内联框架,一个框架虽然包含一个完全独立的页面,并且拥有自己的URL,但却被放置在另一个HTML页面中。 这在网页devise中提供了非常好的可能性。 问题是访问iframe,例如加载一个新的页面。 这个页面解释了如何做到这一点。

框架或对象?

根本的问题是iframe是被看作是一个框架还是一个对象。

  • 正如“ 框架介绍”页面所述,如果使用框架,浏览器会为您创build一个框架层次结构( top.frames[1].frames[2]等)。 iframe是否适合这个框架层次结构?
  • 还是浏览器看到一个iframe作为另一个对象,恰好有一个src属性的对象? 在这种情况下,我们必须使用标准的DOM调用 (如document.getElementById('theiframe'))来访问它。 通常,浏览器允许在“真实”(硬编码)iframe上的两个视图,但是生成的iframe不能作为帧来访问。

NAME属性

最重要的规则是给你的任何iframe创build一个name属性,即使你也使用了一个id

 <iframe src="iframe_page1.html" id="testiframe" name="testiframe"></iframe> 

大多数浏览器需要name属性才能使iframe成为框架层次结构的一部分。 一些浏览器(特别是Mozilla)需要这个id来使iframe可以作为一个对象来访问。 通过将这两个属性分配给iframe,您可以保持打开选项。 但nameid更重要。

访问

要么作为对象访问iframe并更改其src要么作为框架访问iframe并更改其location.href

document.getElementById('iframe_id')。src ='newpage.html'; frames ['iframe_name']。location.href ='newpage.html'; 帧语法稍微好一点,因为Opera 6支持它,但不支持对象语法。

访问iframe

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

 frames['testiframe'].location.href 

句法。 据我所知,这总是有效的。

访问文档

访问iframe中的文档非常简单,只要使用name属性即可。 要计算iframe中文档中链接的数量,请执行frames['testiframe'].document.links.length

生成iframe

当您通过W3C DOM生成iframe时,iframe不会立即进入frames数组,而frames['testiframe'].location.href语法将不会立即生效。 浏览器需要一点时间才能在数组中显示iframe,在这段时间内没有脚本可以运行。

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

除了在Opera中,链接的target属性不能和生成的iframe一起工作,即使我给了我生成的iframe两个name和一个id

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

在iframe中的文本大小

一个好奇的Explorer 6唯一的bug:

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

继续JoelAnair的回答:

为了更健壮,使用如下:

 var el = document.getElementById('targetFrame'); if(el.contentWindow) { el.contentWindow.targetFunction(); } else if(el.contentDocument) { el.contentDocument.targetFunction(); } 

像魅力:)

Folinging 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'); getIframeWindow(el).targetFunction(); ... 
  $("#myframe").load(function() { alert("loaded"); }); 

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

 window.location.reload(); 

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

 window.parent.location.reload(); 

两者都有效。

如果我们要从编码生成的iframe中调用父页面的javascript函数。 前阴影盒或灯箱

window.parent.targetFunction();

这些答案中的一些没有解决CORS问题,或者在放置代码片段的地方使其不太明显。

这是一个具体的例子。 假设我想单击父页面上的一个button,并在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内部的button来调用iframe之外的方法),只需切换代码片段所在的位置,然后更改:

 document.getElementById('my_iframe').contentWindow.postMessage('foo','*'); 

对此:

 window.parent.postMessage('foo','*') 

试试parent.myfunction()

使用以下命令在父页面调用一个框架的function

 parent.document.getElementById('frameid').contentWindow.somefunction()