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

前提是你 提交于 2020-01-20 08:42:13

问题


I'm injecting all my js code to front page, but it needs pictures for ui and stuff, that can be imported only with the help of chrome.extension.getUrl and can be called only from content-script, so I've found tons of advices how to pass data to content page, and nothing of about how pass data back, is it possible at all?

My code now looks like this:

my js code, that will be injected with other code:

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);

content-script:

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

And, obviously, I get document.contentReady is not a function But declaring function in document was the only(!) advice of about how to pass data back from content-script after about 2 hours of googling.


回答1:


Nothing stops you from making the CustomEvent-based communication bi-directional, and it can pass data with detail property:

// 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);
});    

A more in-depth answer can be found here.

However, you should ask yourself whether you even need the page-level script to query for data, since you fully control when it's injected. You can use uni-directional approach after you make sure the code has executed:

// 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);



回答2:


You can pass JS data to the page by creating a new script tag. For example:

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

So for your particular example, you should be able to do:

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

Not pretty (what is when you're working with overwriting content scripts?) but it works.




回答3:


Content Scripts do not share window object with normal scripts on the page. Both of them work on different context.

In your case, you are registering an event listener on window and listening for the event on other context (window). Hence, your event listener will never be called.

However, there is one alternative approach I can see to communicate between content script and normal script is by using MutationObserver.

Idea

  1. Define a node with some Id under which you will create subnodes corresponding to an event.
  2. Register Mustation Observer in your script.
  3. From content script, add the nodes with data as data-* api.

Implementation Example

Content Script
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));
};

Normal Script for registering 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'));

Links

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

Working Example:

I have used the same approach in Requestly Chrome Extension for submitting events to Google Analytics.

  1. Content Script: https://github.com/requestly/chrome-extension/blob/master/src/Shared/utils.js#L26
  2. Normal Script: https://github.com/requestly/web/blob/gh-pages/js/scripts/tracker.js#L35


来源:https://stackoverflow.com/questions/33991572/how-to-pass-data-from-content-script-to-page-level

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!