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

时间:2008-10-30 19:27:56

标签: javascript html iframe

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

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

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

17 个答案:

答案 0 :(得分:522)

假设您的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 :(得分:141)

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

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

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

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

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

  5. 完全有可能子iframe尚未加载,或者其他错误使其无法访问。您可能会发现更容易扭转通信流:也就是说,让子iframe在加载完成后通知其window.parent脚本并准备好回调。通过将其自己的对象之一(例如回调函数)传递给父脚本,该父级可以直接与iframe中的脚本进行通信,而不必担心与之关联的HTMLIFrameElement。

答案 2 :(得分:64)

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

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

  1. 父页面和iframe页面来自不同的域。
  2. 他们使用不同的协议,一个在http://上,另一个在https://。
  3. 这种限制的任何解决方法都是非常不安全的。

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

答案 3 :(得分:30)

在IFRAME中,将您的函数公开给window对象:

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

要从父页面进行访问,请使用:

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

答案 4 :(得分:16)

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

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

此脚本首先检查域是否为预期的域,然后查看消息,该消息将显示给用户,或者通过向首先发送消息的文档发回消息来响应。 / p>

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

答案 5 :(得分:9)

仅仅为了记录,我今天遇到了同样的问题,但这次页面嵌入了一个对象,而不是iframe(因为它是一个XHTML 1.1文档)。以下是它如何与对象一起使用:

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

(抱歉丑陋的换行符,不适合单行)

答案 6 :(得分:8)

IFRAME应该在frames[]集合中。使用像

这样的东西
frames['iframeid'].method();

答案 7 :(得分:8)

Quirksmode有post on this

由于该页面现已中断,并且只能通过archive.org访问,我在此处重现:

<强> I-帧

在此页面上,我简要介绍了从他们所在页面访问iframe的情况。毫不奇怪,有一些浏览器考虑因素。

iframe是一个内联框架,虽然它包含一个带有自己URL的完全独立的页面,但仍然放在另一个HTML页面中。这为网页设计提供了非常好的可能性。问题是访问iframe,例如将新页面加载到其中。本页介绍了如何操作。

框架或对象?

根本问题在于iframe是被视为一个框架还是一个对象。

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

NAME属性

最重要的规则是,即使您还使用name,也要为任何iframe创建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

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

访问文档

如果您使用name属性,则访问iframe内的文档非常简单。要计算iframe中文档中的链接数,请执行此操作 frames['testiframe'].document.links.length

生成的iframe

当您通过W3C DOM生成iframe时,iframe不会立即输入到frames数组中,并且frames['testiframe'].location.href语法将无法立即生效。在数组中iframe出现之前,浏览器需要一点时间,在此期间不会运行任何脚本。

document.getElementById('testiframe').src语法适用于所有情况。

链接的target属性无法使用生成的iframe,但在Opera中除外,即使我为生成的iframe提供了nameid

缺少target支持意味着您必须使用JavaScript来更改生成的iframe的内容,但由于您无论如何都需要JavaScript来生成它,我不会看到这么多一个问题。

iframe中的文字大小

好奇的Explorer 6唯一错误:

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

答案 8 :(得分:7)

我找到了一个很优雅的解决方案。

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

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

示例:

在父母身上:

function tunnel(fn) {
    fn();
}

关于iframe:

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

parent.tunnel(myFunction);

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

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

答案 9 :(得分:4)

其中一些答案并未解决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','*')

答案 10 :(得分:3)

继续JoelAnair's回答:

为了更强大,请使用如下:

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

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

像魅力一样工作:)

答案 11 :(得分:3)

给予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();
  ...
}
...

答案 12 :(得分:2)

同样的事情,但更容易的方式是How to refresh parent page from page within iframe。 只需调用父页面的函数来调用javascript函数来重新加载页面:

window.location.reload();

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

window.parent.location.reload();

两者都有效。

答案 13 :(得分:2)

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

答案 14 :(得分:1)

如果我们想从编码生成的iframe调用父页面javascript函数。 ex shadowbox或lightbox

window.parent.targetFunction();

答案 15 :(得分:1)

只试用parent.myfunction()

答案 16 :(得分:-3)

使用以下方法调用父页面中框架的功能

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