有没有办法找出哪个 iframe 正在调用父级的 JavaScript 函数



下面是一个例子

父母.html

<script>
function printWhoCalledMe() {
  console.log(???);  // what goes here that will identify the caller?
}
<iframe src="iframe1.html"></iframe>
<iframe src="iframe2.html"></iframe>

iframe1.html

<script>
window.parent.printWhoCalledMe();
</script>

iframe2.html

<script>
window.parent.printWhoCalledMe();
</script>

更大的问题是,我有一个测试工具,可以在 iframe 中一次运行一堆测试。每个测试调用window.parent.reportOnTest(success)

我正在考虑通过在超过 1 个 iframe 中运行它们来并行化测试,但我必须通过每个测试,目前有 1000 个测试,并将它们的调用从 window.parent.reportOnTest(success) 更改为类似 window.parent.reportOnTest(success, window.location.href) 或类似的东西。

我想知道是否有办法在不修改测试的情况下找出哪个测试正在调用父级。

注意:我试过了

function printWhoCalledMe() {
  console.log(window.location.href);
}

但那是打印父母的 href。

我担心你可能不得不使用这样的字符串值。

function printWhoCalledMe(callerPage) {
  console.log(callerPage);  // what goes here that will identify the caller?
}

你可以用这样的参数从你的子框架调用这个函数。

iframe1.html

<script>
window.parent.printWhoCalledMe("iframe1");
</script>

iframe2.html

<script>
window.parent.printWhoCalledMe("iframe2");
</script>

如果使用apply调用父函数,则可以将上下文更改为帧window

window.parent.printWhoCalledMe.apply(this);
function printWhoCalledMe() {
  console.log(this); // this now refers to the frame window
}

太笨拙了,但你可以使用这样的东西:

  1. 使用 caller 获取对调用所需函数的函数的引用。
  2. 继续使用Object.getPrototypeOf,直到你达到那个境界的Object.prototype
  3. 迭代所有框架窗口,并比较Object.prototype
  4. 找到匹配项后,使用 frameElement 获取 iframe。

这需要同源、无沙盒和草率模式。例:

window.func = function func() {
  var proto, nextProto = func.caller;
  while (nextProto) {
    proto = nextProto;
    nextProto = Object.getPrototypeOf(proto);
  }
  var win = [].find.call(window.frames, function(win) {
    try {
      return win.Object.prototype === proto;
    } catch(err) {
      return false;
    }
  });
  if (win) {
    var iframe = win.frameElement;
    console.log("function called from frame " + iframe.name);
  }
};
var iframe = document.createElement('iframe');
iframe.name = "myframe";
document.body.appendChild(iframe);
var doc = iframe.contentDocument;
var script = doc.createElement('script');
script.text = "(function f(){parent.func()})()";
doc.body.appendChild(script);
// Logs "function called from frame myframe"

调用父函数时,如果不将其包含在参数中,则无法获取此信息。

幸运的是,这很容易。假设你给每个 iframe 一个 id,你只需要将 iframe 的 id 传递给你正在调用的函数。你可以像这样获取你所在的 iframe 的 id:window.frameElement.id

所以例如:

iframe1.html

<script>
    window.parent.printWhoCalledMe(window.frameElement.id);
</script>

父母.html

<script>
    function printWhoCalledMe(iframeId) {
        console.log(iframeId);  // Prints the id of the iframe that called the function
    }
</script>

最新更新