如何获取所有帧以访问一个单一全局变量?

3

我正在开发一个Chrome扩展程序,需要让我的内容脚本可以访问网页的所有框架,以便检测某些特定字段。

一旦检测到,我将尝试将该字段元素存储在全局对象的相应属性内。问题是,如果这些元素都位于不同的iframe中,每个iframe都会获得该脚本的副本,并填充其自己的对象副本而不是单个全局对象。

是否有一种方法可以拥有一个单一的全局对象实例,并在每次检测到字段时将值附加到其属性上?

例如:

原始对象

{
    userName: [],
    email: []
}

检测到 iframe1 中的 userName 字段。
{
    userName: [<input id="username">...</input>],
    email: []
}

检测到iframe2中的电子邮件字段。
{
    userName: [],
    email: [<input id="email">...</input>]
}

期望结果

{
    userName: [<input id="username">...</input>],
    email: [<input id="email">...</input>]
}

我不禁想象一个通过广告软件安装的Chrome扩展程序,能够从Stripe的iframe中获取信用卡信息。但这在设计上本不应该是可能的。 - Salim Djerbouh
@CaddyDZ 我相信可以通过 window.postMessage 实现嵌入式页面通信,但我不确定如何检测窗口是否嵌入在 DOM 中(iframe),以及父窗口应该如何处理这些消息,都在同一个 content-script.js 文件中。 - Noam Suissa
1
意图没有问题,这是一个完全有效的任务。我刚刚在如何修复Chrome扩展程序上的多个确认窗口中写了类似的东西,但当然可能有更好的例子。或者也许我今天稍后会根据您的用例调整我的代码。 - wOxxOm
1个回答

2

通过扩展消息传递到后台脚本来组织通信将更加安全可靠。内容脚本实例运行在主页面和所有iframe中,主要的实例等待数据,其他iframe通过后台页面中继发送数据。

内容脚本:

if (window === top) {
  // main page
  const data = {};
  chrome.runtime.onMessage.addListener(msg => {
    Object.assign(data, msg.data);
    if (data.email && data.username) {
      console.log('Got both values', data);
    }
  });
} else {
  // inside a frame
  const data = {};
  for (const id of ['username', 'email']) {
    const el = document.getElementById(id);
    if (el) data[id] = el.value; 
  }
  if (Object.keys(data).length)
    chrome.runtime.sendMessage({data});
}

后台脚本

chrome.runtime.onMessage.addListener((msg, sender) => {
  // message from a frame?
  if (msg.data && sender.frameId) {
    // relay it to the main page (frameId: 0)
    chrome.tabs.sendMessage(sender.tab.id, msg, {frameId: 0});
  }
});

谢谢!这很有道理。然而,是要传递整个元素本身。不知何故,在background.js文件中记录msg时,该元素为空,但根据日志记录,它被检测到存在。有没有解决方法? - Noam Suissa
我不明白。也许你看错了控制台 - wOxxOm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接