GreaseMonkey - 在同一选项卡中的两个脚本 运行 之间共享数据

GreaseMonkey - sharing data between two scripts running in same tab

有没有办法在同一个选项卡中 运行ning 的两个不同的 greasemonkey 脚本之间共享数据?我尝试只设置 document 的 属性,但它没有用。

为了举例,两个脚本都是这样的:

if (document.shared === undefined) {
    document.shared = 0;
}
document.shared++;

当这是 运行 时,无论脚本以什么顺序执行,每个脚本都会初始化变量并将其递增到 1(根据实际脚本中的日志记录),而不是仅其中一个初始化然后共享变量。

似乎,对于用户定义的属性,每个 GM 脚本都有自己的 document 副本,这根本不是我想要的。

P.S。显然,调用类似 document.getElementById() 的两个 GreaseMonkey 脚本将访问同一页面,但显然不是针对用户定义的属性。

这两个脚本实际上 运行 在一个沙箱中,并且无法访问彼此及其属性。我认为在这两个属性之间进行通信的最佳方式是在 HTML 中创建一个通信元素,其中包含一些 JSON 或只是一些数据作为 属性 并以这种方式进行通信。然后定期检查具有预定 ID 的元素,在找到时解码 JSON 并发回一些数据。

请记住,范围的任何实例和数据之间的链接都不会保留。这意味着您不能以这种方式传递任何函数以防止您仍然在脚本之间进行通信,但只要传递一些数据(例如数组、对象、数字或字符串)就应该没有问题 JSON.stringify他们。

您可以使用网络消息,例如

var me = /* some id */;
window.addEventListener("message", function(e) {
  if(e.origin === location.origin && typeof e.data === 'object' && e.data.sender !== me) {
    console.log('received in script ' + me +': ', e.data.data);
  }
});
document.addEventListener('DOMContentLoaded', function() {
  window.postMessage({sender: me, data: 'message from script ' + me}, location.origin);
});

如果您使用 me = 1me = 2 两次该脚本,您将看到

received in script 2: message from script 1
received in script 1: message from script 2

一些注意事项:

  • 运行 脚本与 @run-at document-start 等到 DOMContentLoaded 才发送数据。这样您就可以确定已经添加了事件侦听器。

  • 如果你使用@grant none,页面将能够通过修改addEventListenerpostMessage.

    来劫持消息传递

    为避免这种情况,您可以使用例如@grant GM_info。这也将提供一种为 me 生成 id 的方法(如果您不关心将此信息泄漏到页面):

    me = GM_info.script.name + GM_info.script.namespace;
    
  • 该页面将能够读取您的脚本发送的消息,甚至可以像您的任何脚本一样向您的脚本发送消息。

    所以不要发送敏感数据,也不要相信收到的数据。