如何将数据从内容脚本传递到页面级别?

How to pass data from content-script to page-level?

我正在将我所有的 js 代码注入首页,但它需要 ui 的图片和其他东西,只能在 chrome.extension.getUrl 的帮助下导入并且只能从content-script,所以我找到了很多关于如何将数据传递到内容页面的建议,但没有关于如何将数据传回的建议,这是否可能?

我的代码现在看起来像这样:

我的 js 代码,将与其他代码一起注入:

var Content = {};
$(document).contentReady = function(content) {
    Content = content;
    $(document).ready(function () {/*cool stuff here, that require content*/});
}
var event = new CustomEvent('LoadContent');
window.dispatchEvent(event);

内容脚本:

document.querySelector('head').appendChild(jsCode);
window.addEventListener("LoadContent", function(evt) {
    var content =
    {
        data:   "url(" + chrome.extension.getURL('content.smth') + ")"
    };
    document.contentReady(content);
}, false);

而且,显然,我得到 document.contentReady is not a function 但是在谷歌搜索大约 2 小时后,关于如何从内容脚本传回数据的唯一(!)建议是在文档中声明函数。

您可以通过创建一个新的脚本标签将JS数据传递到页面。例如:

function injectScript(code) {
    var body = document.getElementsByTagName('body')[0];
    var s = document.createElement('script');
    s.innerHTML = code;
    body.appendChild(s);
}
injectScript('var foo = 2;');

因此对于您的特定示例,您应该能够做到:

injectScript('document.contentReady({data: url(' + blahblah + '})');

不漂亮(当您使用覆盖内容脚本时是什么?)但它有效。

Content Scripts 不与页面上的普通脚本共享 window 对象。他们都在不同的环境下工作。

在您的例子中,您正在 window 上注册事件侦听器并在其他上下文 (window) 上侦听事件。因此,您的事件侦听器将永远不会被调用。

但是,我可以看到另一种在内容脚本和普通脚本之间进行通信的方法是使用 MutationObserver

想法

  1. 用一些 Id 定义一个节点,您将在该节点下创建与事件对应的子节点。
  2. 在您的脚本中注册 Mustation Observer。
  3. 从内容脚本中,添加数据为 data-* api.
  4. 的节点

实现示例

内容脚本
var submitEvent = function(category, action, label) {
  var eventObserverPlaceholder = document.getElementById('events-observer-placeholder'),
    $eventEl = $('<span></span>').attr({
      'data-category': category,
      'data-action': action,
      'data-label': label
    });

  eventObserverPlaceholder.appendChild($eventEl.get(0));
};

用于注册 Mutation Observer 的普通脚本:

RQ.Methods.addObserverForEvents = function(targetNode) {
  var observer = new MutationObserver(RQ.Methods.handleMutationList);

  // Notify me when a new child is added
  var observerConfig = {
    attributes: false, 
    childList: true, 
    characterData: false 
  };

  observer.observe(targetNode, observerConfig);
  return observer;
};

RQ.mutationObserver = RQ.Methods.addObserverForEvents(document.getElementById('events-observer-placeholder'));

链接

  1. https://davidwalsh.name/mutationobserver-api
  2. https://developer.mozilla.org/en/docs/Web/API/MutationObserver

工作示例:

我在 Requestly Chrome 扩展中使用相同的方法将事件提交到 Google Analytics。

  1. 内容脚本:https://github.com/requestly/chrome-extension/blob/master/src/Shared/utils.js#L26
  2. 普通脚本:https://github.com/requestly/web/blob/gh-pages/js/scripts/tracker.js#L35

没有什么能阻止您进行基于 CustomEvent 的双向通信,它可以通过 detail 属性:

传递数据
// Page script
window.addEventListener('RecieveContent', function(evt) {
  // do something cool with evt.detail
});
var event = new CustomEvent('LoadContent');
window.dispatchEvent(event);

// Content script
window.addEventListener('LoadContent', function(evt) {
  content = /* ... */
  var event = new CustomEvent('RecieveContent', {detail: content});
  window.dispatchEvent(event);
});    

可以找到更深入的答案

但是,您应该问问自己是否需要页面级脚本来查询数据,因为您可以完全控制何时注入。确保代码已执行后,您可以使用单向方法:

// Page script
window.addEventListener('RecieveContent', function(evt) {
  // do something cool with evt.detail
});    

// Content script
jsCode.onload = function() {
  // This fires after the page script finishes executing
  content = /* ... */
  var event = new CustomEvent('RecieveContent', {detail: content});
  window.dispatchEvent(event);
}
document.querySelector('head').appendChild(jsCode);