问题
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
- Define a node with some Id under which you will create subnodes corresponding to an event.
- Register Mustation Observer in your script.
- From content script, add the nodes with data as
data-*
api.
Implementation Example
Content Scriptvar 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
- https://davidwalsh.name/mutationobserver-api
- 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.
- Content Script: https://github.com/requestly/chrome-extension/blob/master/src/Shared/utils.js#L26
- 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