首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >TamperMonkey -不同子域上脚本之间的消息

TamperMonkey -不同子域上脚本之间的消息
EN

Stack Overflow用户
提问于 2016-12-12 23:47:35
回答 3查看 4.8K关注 0票数 11

我有两个剧本。每一个运行在我们公司"Example.com".的不同子域上。

代码语言:javascript
运行
复制
Script #1 -- house.example.com
Script #2 -- bob.fred.example.com

相同的域不同的子域。

当某个特定元素出现在house.example.com上时,我需要向运行在bob.fred.example.com上的脚本发送一条消息

由于Google扩展可以在扩展之间交换消息,所以TamperMonkey必须有一种方式在同一个扩展范围内,在脚本之间交换消息--特别是当它们运行在同一个二级域时。

谁能给我指明正确的方向?一个或两个例子将值得他们的重量黄金。

Update:虽然Gothdo提到Javascript communication between browser tabs/windows包含了这个问题的答案,但他没有考虑到所涉及的跨源政策。所提到的问题中没有一个能为跨源浏览器标签通信提供一个清晰的答案,这是这个问题的主要观点。我现在已经研究并解决了这个问题,从许多SO和非SO的来源获得了一些想法。如果这个问题重新开始,我会张贴我的解决方案。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-04-06 03:00:55

使用@grant可以启用沙箱,这有时会在尝试与Greasemonkey上的复杂页面对象交互时造成困难。

如果您不想使用@grant启用沙箱,另一个选项是让userscript为另一个域创建一个iframe,然后向它发送一条消息。在另一个域中,在iframe中,侦听消息。当接收到消息时,使用BroadcastChannel将消息发送到该其他域上的每个其他选项卡,运行userscript的其他选项卡可以打开相同的BroadcastChannel并侦听消息。

例如,要在stackoverflow.com上创建一个用户脚本,该脚本可以向运行在example.com上不同选项卡中的用户脚本发送消息

代码语言:javascript
运行
复制
// ==UserScript==
// @name             0 Cross-tab example
// @include          /^https://example\.com\/$/
// @include          /^https://stackoverflow\.com\/$/
// @grant            none
// ==/UserScript==

if (window.location.href === 'https://example.com/') {
  const broadcastChannel = new BroadcastChannel('exampleUserscript');
  if (window.top !== window) {
    // We're in the iframe:
    window.addEventListener('message', (e) => {
      if (e.origin === 'https://stackoverflow.com') {
        broadcastChannel.postMessage(e.data);
      }
    });
  } else {
    // We're on a top-level tab:
    broadcastChannel.addEventListener('message', (e) => {
      console.log('Got message', e.data);
    });
  }
} else {
  // We're on Stack Overflow:
  const iframe = document.body.appendChild(document.createElement('iframe'));
  iframe.style.display = 'none';
  iframe.src = 'https://example.com';

  setTimeout(() => {
    iframe.contentWindow.postMessage('Sending message from Stack Overflow', '*');
  }, 2000);
}

这导致:

如果您想要双向通信,而不仅仅是单向通信,那么让两个父页面创建一个子域iframe到单个目标域(比如example.com)。若要与其他选项卡通信,请将消息发送给孩子iframe。让孩子iframe监听消息,当看到消息时,发布一条BroadcastChannel消息,以便与所有其他iframe通信。当iframe接收到BroadcastChannel消息时,使用postMessage将其中继到父窗口。

代码语言:javascript
运行
复制
// ==UserScript==
// @name             0 Cross-tab example
// @include          /^https://example\.com\/$/
// @include          /^https://(?:stackoverflow|stackexchange)\.com\/$/
// @grant            none
// ==/UserScript==

if (window.location.href === 'https://example.com/') {
  const broadcastChannel = new BroadcastChannel('exampleUserscript');
  if (window.top !== window) {
    // We're in an iframe:
    window.addEventListener('message', (e) => {
      console.log('iframe received message from top window');
      if (e.origin === 'https://stackoverflow.com' || e.origin === 'https://stackexchange.com') {
        broadcastChannel.postMessage(e.data);
      }
    });
    broadcastChannel.addEventListener('message', (e) => {
      console.log('iframe received message from BroadcastChannel');
      window.top.postMessage(e.data, '*');
    });
  }
} else {
  // We're on Stack Overflow or Stack Exchange
  const iframe = document.body.appendChild(document.createElement('iframe'));
  iframe.style.display = 'none';
  iframe.src = 'https://example.com';
  window.addEventListener('message', (e) => {
    if (e.origin === 'https://example.com') {
      console.log(`Top window ${window.origin} received message from iframe:`, e.data);
    }
  });
  if (window.location.href === 'https://stackoverflow.com/') {
    setTimeout(() => {
      console.log('stackoverflow posting message to iframe');
      iframe.contentWindow.postMessage('Message from stackoverflow', '*');
    }, 2000);
  }
}

在上面的代码中,堆栈溢出上的选项卡向Stack Exchange上的选项卡发送消息。结果截图:

票数 2
EN

Stack Overflow用户

发布于 2017-12-19 05:00:49

您可以使用GM_getValueGM_setValueGM_addValueChangeListener来实现跨选项卡用户脚本通信.

在用户脚本头中添加以下行。

代码语言:javascript
运行
复制
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addValueChangeListener

下面的粗代码行将简化跨选项卡用户脚本的通信。

代码语言:javascript
运行
复制
function GM_onMessage(label, callback) {
  GM_addValueChangeListener(label, function() {
    callback.apply(undefined, arguments[2]);
  });
}

function GM_sendMessage(label) {
  GM_setValue(label, Array.from(arguments).slice(1));
}

因此,您所需要做的就是发送和接收消息。

代码语言:javascript
运行
复制
GM_onMessage('_.unique.name.greetings', function(src, message) {
  console.log('[onMessage]', src, '=>', message);
});
GM_sendMessage('_.unique.name.greetings', 'hello', window.location.href);

注意:如果发送的消息与以前相同,则发送消息可能不会触发回调。这是由于GM_addValueChangeListener没有触发,因为值没有更改,也就是说,即使调用了GM_setValue,其值也与以前相同。

票数 8
EN

Stack Overflow用户

发布于 2018-05-31 16:13:19

我最后使用的方法是通过javascript在同一域中的子域之间进行制表符到制表符的通信。(我也尝试使用localStorage,但这在子域之间不起作用。)

场景: SubDomain A上的选项卡A将向SubDomain B上的Tab发送消息:

代码如下所示:

代码语言:javascript
运行
复制
function getCookie(cooVal) {
    var cname = cooVal+ '=';
    var ca = document.cookie.split(';');
    for (var i=0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(cname) === 0) {
            return c.substring(cname.length, c.length);
        }
    }
    return null;
} //END getcookie()

subDomainB上的选项卡B将从subDomain A上的TabA接收消息:

代码语言:javascript
运行
复制
function checkIncomingCIQ(){
    var acciq = getCookie('acciq');
    var jdlwc = getCookie('jdlwc');
}

TabA将向Tab B发送消息,如下所示:

代码语言:javascript
运行
复制
document.cookie="acciq=5; domain=.example.com; path=/";
document.cookie="jdlwc=fubar; domain=.example.com; path=/";

对于任何想知道的人来说,是的,子域可以互相发送消息--这不仅仅是单向的交流。只需在另一个方向复制相同的场景。

当然,在这两个选项卡上,消息传递系统都位于javascript循环中,如下所示:

代码语言:javascript
运行
复制
(function foreverloop(i) {
    //Do all my stuff - send/receive the cookies, do stuff with the values, etc
    setTimeout(function() {
        foreverloop(++i);
    },2000);
}(0)); //END foreverloop

两个选项卡上的TM标头如下所示:

代码语言:javascript
运行
复制
// ==UserScript==
// @namespace    abcd.tops.example.com
// @match        *://abcd.tops.example.*/*
// @grant        none
// @require     http://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
// ==/UserScript==
and
// ==UserScript==
// @namespace    http://mysubdomain.example.com/callcenter/
// @match        *://*.example.com/callcenter/
// @grant        none
// @require     http://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
// ==/UserScript==

对于延迟发布此解决方案向所有人表示歉意。当这个问题被错误地标记为重复之后,人们花了很长时间才把它重新打开,生命就这样继续下去。。。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41111556

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档