如何在父窗口创建的iframe的onload处理程序中获取对iframe窗口对象的引用

blu*_*oon 51 html javascript iframe dom

在我粘贴任何代码之前,这是场景:

  1. 我有一个HTML文档,使用JavaScript创建一个空的iframe
  2. JavaScript创建一个函数并将对该函数的引用附加到iframe的文档对象(doc.open()用于获取对文档的引用)
  3. 然后将该函数作为onloadiframe文档的处理程序附加(通过写入<body onload="...">iframe.

现在让我难过的是onload处理程序中的全局(窗口)和文档对象(在它运行时)与通过脚本节点添加的JavaScript运行的相同对象不同.

这是HTML:

<!doctype html>
<html>
<head>
<script>
(function(){
  var dom,doc,where,iframe;

  iframe = document.createElement('iframe');
  iframe.src="javascript:false";

  where = document.getElementsByTagName('script')[0];
  where.parentNode.insertBefore(iframe, where);

  doc = iframe.contentWindow.document;

  var _doc = document;

  doc.open()._l=function() {
    // the window object should be the one that doc is inside
    window.vanishing_global=new Date().getTime();

    var js = this.createElement("script");
    js.src = 'test-vanishing-global.js?' + window.vanishing_global;

    window.name="foobar";
    this.foobar="foobar:" + Math.random();
    document.foobar="barfoo:" + Math.random();

    // `this` should be the document object, but it's not
    console.log("this == document: %s", this == document);
    console.log("this == doc:      %s", this == doc);

    // the next two lines added based on @Ian's comment below
    console.log("_doc == document: %s", _doc == document);
    console.log("_doc == doc:      %s", _doc == doc);

    console.log("name: " + window.name + "\n" + "window.vanishing_global: " + window.vanishing_global + "\ntypeof window.vanishing_global: " + typeof window.vanishing_global + "\ndocument.foobar: " + document.foobar);
    this.body.appendChild(js);
  };
  doc.write('<body onload="document._l();"></body>');
  doc.close();
})();
</script>
</head>
<body>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

这是test-vanishing-global.js:

console.log("name: " + window.name + "\n" + "window.vanishing_global: " + window.vanishing_global + "\ntypeof window.vanishing_global: " + typeof window.vanishing_global + "\ndocument.foobar: " + document.foobar);
Run Code Online (Sandbox Code Playgroud)

说明:

将这两个文件放入一个目录中,然后在浏览器中打开HTML(在最新的Chrome和Firefox中测试,两者都相同).

这是我得到的输出:

this == document: false
this == doc:      true
_doc == document: true
_doc == doc:      false

name: foobar
window.vanishing_global: 1366037771608
typeof window.vanishing_global: number
document.foobar: barfoo:0.9013048021588475

name: 
window.vanishing_global: undefined
typeof window.vanishing_global: undefined
document.foobar: foobar:0.5015988759696484
Run Code Online (Sandbox Code Playgroud)

this处理程序中的对象应该是文档对象.它一个文档对象,但与它在其中运行的文档不是同一个文档对象(它也与父文档不同).处理程序内的窗口对象也与在页面中加载的JavaScript中运行的窗口对象不同.

最后我的问题是:

有谁知道发生了什么,以及如何获得对实际窗口对象的引用,或者至少从同一个全局上下文声明和引用全局变量?

脚注:

此iframe没有跨域问题,因为它们位于同一个域中.如果有人设置会出现问题document.domain,但在此示例代码中没有完成.

Ian*_*Ian 59

您在父页面中声明了所有内容.所以引用windowdocument是父页面的.如果你想做的东西iframe,iframe || iframe.contentWindow用来访问它window,并iframe.contentDocument || iframe.contentWindow.document访问它document.

对于正在发生的事情有一个词,可能是"词汇范围":什么是词汇范围?

范围的唯一背景是这个.而在你的榜样,该方法的所有者doc,这是iframedocument.除此之外,在此函数中使用已知对象访问的任何内容都是父对象(如果未在函数中声明).如果函数在不同的地方声明,那么它将是一个不同的故事,但它在父页面中声明.

这是我写它的方式:

(function () {
  var dom, win, doc, where, iframe;

  iframe = document.createElement('iframe');
  iframe.src = "javascript:false";

  where = document.getElementsByTagName('script')[0];
  where.parentNode.insertBefore(iframe, where);

  win = iframe.contentWindow || iframe;
  doc = iframe.contentDocument || iframe.contentWindow.document;

  doc.open();
  doc._l = (function (w, d) {
    return function () {
      w.vanishing_global = new Date().getTime();

      var js = d.createElement("script");
      js.src = 'test-vanishing-global.js?' + w.vanishing_global;

      w.name = "foobar";
      d.foobar = "foobar:" + Math.random();
      d.foobar = "barfoo:" + Math.random();
      d.body.appendChild(js);
    };
  })(win, doc);
  doc.write('<body onload="document._l();"></body>');
  doc.close();
})();
Run Code Online (Sandbox Code Playgroud)

由于对范围的误解,它可能会使其不那么混乱,因此别名windoc作为wd不必要.这样,它们就是参数,你必须引用它们来访问它们iframe的东西.如果你想访问父母的,你仍然使用windowdocument.

我不确定将方法添加到document(doc在这种情况下)的含义是什么,但是设置_l方法可能更有意义win.这样,事情可以在没有前缀的情况下运行......例如<body onload="_l();"></body>