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

本文讨论了如何在JavaScript中从父页面调用iframe中的函数,包括使用`window.parent`对象,`postMessage` API进行跨域通信等方法。文中列举了多种场景下的解决方案,并给出了具体代码示例。
摘要由CSDN通过智能技术生成

基本上,我将iframe嵌入到页面中,并且iframe具有一些我需要从父页面调用的JavaScript例程。

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

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


#1楼

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

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

(很抱歉换行太丑,没有一行)


#2楼

跟随尼丁·班萨尔(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();
  ...
}
...

#3楼

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

如您所说,执行位于父文档中的代码非常容易。 这就是我的代码的基础,反之亦然。

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

例:

在父项上:

function tunnel(fn) {
    fn();
}

在iframe上:

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

parent.tunnel(myFunction);

加载iframe时,它将调用parent.tunnel(YourFunctionReference),它将执行参数中接收的功能。

如此简单,而不必处理各种浏览器中的所有非标准方法。


#4楼

使用以下命令来调用父页面中框架的功能

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

#5楼

Quirksmode对此发表了一篇文章

由于该页面现在已损坏,并且只能通过archive.org进行访问,因此在此处进行了复制:

内嵌框架

在此页面上,我将简要概述如何从它们所在的页面访问iframe。 毫不奇怪,有一些浏览器注意事项。

iframe是一个内联框架,该框架虽然包含一个完全独立的页面及其自己的URL,但仍放置在另一个HTML页面中。 这在网页设计中提供了非常好的可能性。 问题是要访问iframe,例如将新页面加载到其中。 此页面说明了操作方法。

框架还是物体?

基本问题是将iframe视为框架还是对象。

  • 框架简介页中所述,如果您使用框架,则浏览器会为您创建框架层次结构( top.frames[1].frames[2]等)。 iframe是否适合此框架层次结构?
  • 还是浏览器将iframe视为另一个对象,而该对象恰好具有src属性? 在这种情况下,我们必须使用标准的DOM调用 (如document.getElementById('theiframe'))进行访问。 通常,浏览器允许在“真实”(硬编码)iframe上同时使用两种视图,但是生成的iframe无法作为框架访问。

NAME属性

最重要的规则是,即使您也使用id ,也要为创建的所有iframe提供一个name属性。

<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'; frame ['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仅bug:

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


#6楼

假设您的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(); 

#7楼

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

frames['iframeid'].method();

#8楼

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

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

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

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

#9楼

这里有一些怪癖要注意。

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

  2. 您也可以尝试HTMLIFrameElement.contentDocument.defaultView ,这是一些较旧的浏览器允许的,但IE不允许。 即使这样,该标准也没有明确指出要返回window对象,原因与(1)相同,但是如果您愿意,可以在此处选择一些其他的浏览器版本。

  3. 返回窗口的window.frames['name']是最早的接口,因此也是最可靠的接口。 但是您必须使用name="..."属性才能按名称获取框架,该框架有点难看/ 不推荐使用 /过渡。 ( id="..."会更好,但IE不喜欢那样。)

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

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


#10楼

可以从iframe调用父级JS函数,但是仅当父级和iframe中加载的页面都来自同一域(即abc.com),并且两者都使用相同的协议(即,两者都位于http://https://

在以下情况下,呼叫将失败:

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

解决此限制的任何方法都将非常不安全。

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


#11楼

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

#12楼

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

#13楼

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

window.location.reload();

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

window.parent.location.reload();

两者都可以。


#14楼

继续JoelAnair的回答:

为了提高鲁棒性,请使用以下方法:

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

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

像魅力一样工作:)


#15楼

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

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


#16楼

如果要从其他函数(例如,shadowbox或lightbox)生成的iframe上调用Parent上的JavaScript函数。

您应该尝试利用window对象并调用父函数:

window.parent.targetFunction();

#17楼

尝试尝试parent.myfunction()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值