问题
Currently, I am creating a WebExtension for Firefox which displays a small div in the active HTML page on the active tab after 6 seconds (not the popup.html in browser_action
!). I made a small example that shows a button in the div. My problem is that I don't know how to detect a click
event of this button so I can kick off a function? In the moment I handle the event listener in content.js
manifest.json:
{
"manifest_version": 2,
"name": "Study06",
"version": "1.0",
"description": "My web extension",
"permissions": [
"tabs",
"<all_urls>",
"alarms"
],
"background": {
"scripts": ["background.js"]
}
}
background.js:
browser.alarms.create("", {delayInMinutes: 0.1});
browser.alarms.onAlarm.addListener(injectScript);
function getActiveTab() {
return browser.tabs.query({active: true, currentWindow: true});
}
function injectScript() {
getActiveTab().then((tabs) => {
browser.tabs.executeScript(null, {
file: "/content.js"
});
// send message to contentscript
browser.tabs.sendMessage(tabs[0].id, {message: "Hello"});
});
}
After 6 seconds, content.js will be loaded and a message to content.js will be sent.
content.js:
document.addEventListener('DOMContentLoaded', function() {
var button = document.getElementById('button_id');
button.addEventListener('click', function() {
console.log("CLICK");
});
});
browser.runtime.onMessage.addListener(createModal);
function createModal(){
document.getElementsByTagName('body')[0].appendChild(modal1);
}
//create div with button
var modal1 = document.createElement("div");
modal1.style.paddingTop = "100px";
modal1.setAttribute("id", "mymodal1");
modal1.style.position = "fixed";
modal1.style.top = 0;
modal1.style.left = 0;
modal1.style.zIndex = 1000000;
modal1.style.overflow = "auto";
var button1 = document.createElement("button");
button1.setAttribute("id", "button_id");
button1.innerHTML = "Click me";
modal1.appendChild(button1);
The event listener in content.js is not working.
I also created a JavaScript file javascriptForButtonEvent.js with an event listener for the button and added this script in manifest content_script
. Also, to inject this file in background script like:
browser.tabs.executeScript(null, {
file: "/content.js";
file: "/javascriptForButtonEvent.js"
});
But, these solutions didn't work for me (when clicking the button nothing happens). Is there a way to handle events from the active HTML page?
回答1:
Your click
event listener never gets added to the DOM. You have:
document.addEventListener('DOMContentLoaded', function() {
When injecting scripts, unless you are explicitly injecting at document_start, your script is guaranteed to be injected at least after DOMContentLoaded
has already fired.1 Given that the event has already fired, and only fires once, your DOMContentLoaded
listener is never called. As a result of how injection works, you do not need to listen for the DOMContentLoaded
event at all. Just move your initialization such that it executes in the main sequence of your code (after you add the button):
document.getElementById('button_id').addEventListener('click', function() {
console.log("CLICK");
});
No need to search for the <button>
you create
However, in this case, you are adding this button yourself. There is no need to go searching for it in the DOM. You already have a reference to it. Add the listener at the time you are creating the button:
var button1 = document.createElement('button');
button1.id = 'button_id';
button1.textContent = 'Click me';
button1.addEventListener('click', function() {
console.log("CLICK");
});
modal1.appendChild(button1);
Don't use generic IDs or classes
For extensions, you should not use IDs or classes that are as generic as button_id
. Doing so results in a good chance that you will have a name collision with the random pages into which you are injecting content. You should pick a sequence of text which you use as a "namespace". You can then prepend this namespace to all IDs and classes. For instance, your ID should be something like: Study06-button_id
. Exactly what you use is a personal choice. But, it should be specific to the extension you are working on.
When listening for DOMContentLoaded, you should check readyState
Any time you use a DOMContentLoaded
listener, or a window
load
listener, you should always check the document.readyState to make sure that you are adding the listener prior to the DOMContentLoaded
event being fired (or load
event, if that is what you are listening for). This should be normal habit when you want to listen for these events. If you add the listener after the event has fired, the listener will never be run.
For adding a DOMContentLoaded
listener, you should use something like:
if(document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded',afterLoaded);
} else {
afterLoaded();
}
function afterLoaded(){
//Everything that needs to happen after the DOM has initially loaded.
}
- Note that when using tabs.executeScript() you have to seriously work at having your
tabs.executeScript()
execute in a time-frame where the script is actually injected atdocument_start
. The exact timing that is needed is different for different browsers. If you use a manifest.jsoncontent_script
entry, this timing is handled by the browser.
来源:https://stackoverflow.com/questions/42553455/detect-and-handle-a-button-click-in-the-active-html-page