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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16018598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 07:34:26  来源:igfitidea点击:

How to get a reference to an iframe's window object inside iframe's onload handler created from parent window

javascripthtmldomiframe

提问by bluesmoon

Before I paste any code, here's the scenario:

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

  1. I have an HTML document that creates an empty iframe using JavaScript
  2. The JavaScript creates a function and attaches a reference to that function to the iframe's document object (using doc.open()to get a reference to the document)
  3. The function is then attached as an onloadhandler for the iframe's document (by writing <body onload="...">into the iframe.
  1. 我有一个 HTML 文档,它使用 JavaScript 创建一个空的 iframe
  2. JavaScript 创建一个函数并将对该函数的引用附加到 iframe 的文档对象(doc.open()用于获取对文档的引用)
  3. 然后将该函数附加为onloadiframe 文档的处理程序(通过写入 iframe.xml 文件)<body onload="...">

Now what has me stumped is that the global (window) and document objects inside the onload handler (while it's running) is different from the same objects run through JavaScript added via script nodes.

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

Here's the HTML:

这是 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>

And here's test-vanishing-global.js:

这是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);

Instructions:

指示:

Put these two files into a directory, and open the HTML in a browser (tested in latest Chrome and Firefox, same result in both).

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

This is the output I get:

这是我得到的输出:

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

The thisobject inside the handler should be either the document object. It isa document object, but not the same document object as the document that it runs inside (it's also not the same as the parent document). The window object inside the handler is also not the same as the window object that runs in JavaScript loaded in the page.

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

So finally my question:

所以最后我的问题是:

Does anyone know what's going on, and how I can either get a reference to the actual window object, or at least declare and reference global variable from the same global context?

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

Footnotes:

脚注:

There are no cross-domain issues with this iframe since they're on the same domain. There is an issue if someone sets document.domain, but that's not being done in this example code.

此 iframe 不存在跨域问题,因为它们位于同一域中。如果有人设置了document.domain,则会出现问题,但在此示例代码中并未这样做。

回答by Ian

You're declaring everything in the parent page. So the references to windowand documentare to the parent page's. If you want to do stuff to the iframe's, use iframe || iframe.contentWindowto access its window, and iframe.contentDocument || iframe.contentWindow.documentto access its document.

您在父页面中声明所有内容。所以引用windowdocument是对父页面的。如果您想对iframe's 进行操作,请使用iframe || iframe.contentWindow访问其window,并iframe.contentDocument || iframe.contentWindow.document访问其document.

There's a word for what's happening, possibly "lexical scope": What is lexical scope?

有一个词来说明正在发生的事情,可能是“词法范围”:什么是词法范围?

The only context of a scope is this. And in your example, the owner of the method is doc, which is the iframe's document. Other than that, anything that's accessed in this function that uses known objects are the parent's (if not declared in the function). It would be a different story if the function were declared in a different place, but it's declared in the parent page.

范围的唯一上下文是 this。在您的示例中,该方法的所有者是doc,即iframe's document。除此之外,在此函数中使用已知对象访问的任何内容都是父对象(如果未在函数中声明)。如果函数在不同的地方声明,但它是在父页面中声明的,那将是另一回事。

This is how I would write it:

我会这样写:

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

The aliasing of winand docas wand daren't necessary, it just might make it less confusing because of the misunderstanding of scopes. This way, they are parameters and you have to reference them to access the iframe's stuff. If you want to access the parent's, you still use windowand document.

的别名win,并docwd是没有必要的,它只是可能使其不易混淆,因为范围的误解。这样,它们是参数,您必须引用它们才能访问iframe's 的东西。如果你想访问父级,你仍然使用windowand document

I'm not sure what the implications are of adding methods to a document(docin this case), but it might make more sense to set the _lmethod on win. That way, things can be run without a prefix...such as <body onload="_l();"></body>

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