代码之家  ›  专栏  ›  技术社区  ›  Tamas Czinege

从父页调用iframe中的javascript代码

  •  572
  • Tamas Czinege  · 技术社区  · 16 年前

    基本上,我有一个 iframe 嵌入到一个页面中, 伊夫拉姆 有一些 JavaScript 我需要从父页面调用的例程。

    现在相反很简单,你只需要打电话 parent.functionName() 但不幸的是,我需要的恰恰相反。

    请注意,我的问题不是更改源 URL 伊夫拉姆 ,但调用 伊夫拉姆 .

    17 回复  |  直到 6 年前
        1
  •  515
  •   Chris jorelli    8 年前

    假设您的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(); 
    
        2
  •  140
  •   Dominique Fortin    12 年前

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

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

    2. 你也可以试试 HTMLIFrameElement.contentDocument.defaultView ,这是一些旧浏览器允许的,但IE不允许的。即使如此,标准并没有明确地说明 窗口 对象返回,原因与(1)相同,但如果您愿意,可以在这里选择一些额外的浏览器版本。

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

    4. window.frames[number] 也是非常可靠的,但知道正确的指数才是诀窍。如果你知道你的页面上只有一个iframe,你就可以摆脱这种困境。

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

        3
  •  63
  •   David Locke    12 年前

    从调用父JS函数 iframe 是可能的,但仅当父级和页面同时加载到 伊夫拉姆 来自同一个域,即abc.com,并且两者都使用相同的协议,即两者都处于打开状态 http:// https:// .

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

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

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

    例如,假设我注册了域名superwiningcompute.com并发送了指向人们电子邮件的链接。当他们加载主页时,我可以隐藏一些 伊夫拉姆 在那里,阅读他们的脸谱网饲料,查看最近的亚马逊或贝宝交易,或者-如果他们使用的服务没有实现足够的安全性-转移钱从他们的帐户。这就是为什么JavaScript被限制在相同的域和相同的协议中。

        4
  •  30
  •   Tomalak    13 年前

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

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

    若要从父页访问,请使用:

    var iframe = document.getElementById("iframeId");
    iframe.contentWindow.myFunction(args);
    
        5
  •  16
  •   19greg96    8 年前

    如果iframe和包含该文档的域不同,则以前发布的方法可能不起作用,但有一个解决方案:

    例如,如果文档A包含一个包含文档B的iframe元素,并且文档A中的脚本在文档B的窗口对象上调用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);
        }
      }
    }
    

    此脚本首先检查域是否为预期域,然后查看消息,该消息要么显示给用户,要么通过将消息发送回最初发送消息的文档来响应。

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

        6
  •  9
  •   Tamas Czinege    15 年前

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

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

    (不好意思出现难看的断线,不适合一行)

        7
  •  8
  •   Michael Berkowski    13 年前

    iframe应该在 frames[] 收集。使用类似的东西

    frames['iframeid'].method();
    
        8
  •  8
  •   Radu    12 年前

    Quirksmode有一个 post on this .

    由于该页面现在已被破坏,并且只能通过archive.org访问,所以我在这里复制了它:

    iFrAMES

    在此页面上,我简要概述了如何从其所在的页面访问iframes。不足为奇,有一些浏览器方面的考虑。

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

    框架还是物体?

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

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

    名称属性

    最重要的规则是给您创建的任何iframe name 属性,即使您还使用 id .

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

    大多数浏览器都需要 名称 属性使iframe成为框架层次结构的一部分。一些浏览器(尤其是Mozilla)需要 身份证件 使iframe作为对象可访问。通过将这两个属性分配给iframe,可以保持选项的打开状态。但是 名称 远比 身份证件 .

    通路

    您可以作为对象访问iframe并更改其 src 或者将iframe作为帧访问并更改其 location.href .

    document.getElementByID('iframe_id').src='newpage.html'; 帧['iframe_name'].location.href='newpage.html'; 框架语法稍好一点,因为Opera6支持它,但不支持对象语法。

    访问iframe

    因此,要获得完整的交叉“浏览器体验,您应该为iframe命名并使用

    frames['testiframe'].location.href
    

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

    访问文档

    如果使用 名称 属性。要计算iframe中文档中的链接数,请执行以下操作: frames['testiframe'].document.links.length .

    生成的iframes

    当您通过 W3C DOM iframe没有立即输入到 frames 不过,数组和 frames['testiframe'].location.href 语法不会立即起作用。在数组中出现iframe之前,浏览器需要一点时间,在这个时间段内没有脚本可以运行。

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

    这个 target 链接的属性也不适用于生成的iframe,除非在opera中,即使我将生成的iframe 名称 和一个 身份证件 .

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

    iframes中的文本大小

    一个好奇的探险家6唯一的错误:

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

        9
  •  7
  •   Julien L    10 年前

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

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

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

    例子:

    父母:

    function tunnel(fn) {
        fn();
    }
    

    关于IFRAME:

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

    加载iframe时,它将调用parent.tunnel(yourfunctionreference),该函数将执行参数中接收的函数。

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

        10
  •  4
  •   Cybernetic    7 年前

    其中一些答案没有解决CORS问题,或者没有使代码片段放在哪里使通信成为可能变得明显。

    这是一个具体的例子。假设我想单击父页面上的一个按钮,并让它在iframe中执行一些操作。以下是我的方法。

    父级\u 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页面.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','*')
    
        11
  •  3
  •   Community basarat    7 年前

    继续进行 JoelAnair's 答:

    为了更稳健性,使用如下:

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

    像魅力一样工作:)

        12
  •  3
  •   Dominique Fortin    6 年前

    下面是尼廷·班萨尔的回答

    为了更加坚固:

    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();
      ...
    }
    ...
    
        13
  •  2
  •   GeverGever    16 年前
           $("#myframe").load(function() {
                alert("loaded");
            });
    
        14
  •  2
  •   Sangam Uprety    13 年前

    同样的事情,但更简单的方法是 How to refresh parent page from page within iframe . 只需调用父页面的函数即可调用javascript函数来重新加载页面:

    window.location.reload();
    

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

    window.parent.location.reload();
    

    两者都有效。

        15
  •  1
  •   Santhanakumar    13 年前

    如果我们想从编码生成的iframe调用父页面javascript函数。前暗箱或灯箱

    window.parent.targetFunction();

        16
  •  1
  •   Saeid    13 年前

    试一试 parent.myfunction()

        17
  •  -3
  •   Vaibs_Cool    10 年前

    使用以下命令调用父页中框架的函数

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