在父页面的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();
有一些怪癖在这里知道。
-
HTMLIFrameElement.contentWindow
可能是更简单的方法,但它不是一个标准的属性,一些浏览器不支持它,大多数是旧的。 这是因为DOM级别1的HTML标准对window
对象没有什么可说的。 -
你也可以尝试
HTMLIFrameElement.contentDocument.defaultView
,这是几个较旧的浏览器允许,但IE不。 即便如此,标准并没有明确地说你得到window
对象,出于与(1)相同的原因,但是如果你关心的话,你可以在这里select一些额外的浏览器版本。 -
window.frames['name']
返回窗口是最老的,因此也是最可靠的接口。 但是,你必须使用name="..."
属性来获得一个名字,这是一个丑陋/不赞成/过渡的框架。 (id="..."
会更好,但IE不喜欢。) -
window.frames[number]
也是非常可靠的,但知道正确的索引是诀窍。 你可以摆脱这个例如。 如果你知道你只有一个页面上的iframe。 -
孩子iframe还没有加载完全可能,或者是其他的错误使得它无法访问。 您可能会发现,更改通信stream程更容易:也就是说,当子结点加载完成并准备好callback时,让子结点的iframe通知其
window.parent
脚本。 通过将自己的一个对象(例如callback函数)传递给父脚本,该父母就可以直接与iframe中的脚本进行通信,而不必担心与其关联的HTMLIFrameElement。
从iframe
调用一个父JS函数是可能的,但只有当父母和加载在iframe
中的页面来自同一个域,即abc.com,并且都使用相同的协议,即都在http://
或https://
。
在下面提到的情况下,呼叫将失败:
- 父页面和iframe页面来自不同的域。
- 他们使用不同的协议,一个是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); } } }
这个脚本首先检查域是预期的域,然后查看它向用户显示的消息,或者通过将消息发回到首先发送消息的文档来响应。
为了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,您可以保持打开选项。 但name
比id
更重要。
访问
要么作为对象访问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()