Eine Webseite modifizieren
Eine der häufigsten Anwendungsfälle für eine Erweiterung ist die Modifikation einer Webseite. Zum Beispiel könnte eine Erweiterung den Stil einer Seite ändern, bestimmte DOM-Knoten verbergen oder zusätzliche DOM-Knoten in die Seite einfügen wollen.
Es gibt zwei Möglichkeiten, dies mit WebExtensions-APIs zu tun:
- Deklarativ: Definieren Sie ein Muster, das eine Gruppe von URLs abgleicht, und laden Sie eine Gruppe von Skripten in Seiten, deren URL diesem Muster entspricht.
- Programmgesteuert: Verwenden Sie eine JavaScript-API, um ein Skript in die Seite zu laden, die von einem bestimmten Tab gehostet wird.
In beiden Fällen werden diese Skripte Content-Skripte genannt und unterscheiden sich von den anderen Skripten, die eine Erweiterung ausmachen:
- Sie haben nur Zugriff auf einen kleinen Teil der WebExtension-APIs.
- Sie haben direkten Zugriff auf die Webseite, in die sie geladen werden.
- Sie kommunizieren mit dem Rest der Erweiterung über eine Nachrichtenschnittstelle.
In diesem Artikel betrachten wir beide Methoden, um ein Skript zu laden.
Seiten modifizieren, die einem URL-Muster entsprechen
Erstellen Sie zunächst ein neues Verzeichnis namens "modify-page". Erstellen Sie in diesem Verzeichnis eine Datei namens "manifest.json" mit folgendem Inhalt:
{
"manifest_version": 2,
"name": "modify-page",
"version": "1.0",
"content_scripts": [
{
"matches": ["https://developer.mozilla.org/*"],
"js": ["page-eater.js"]
}
]
}
Der Schlüssel content_scripts
gibt an, wie Sie Skripte in Seiten laden, die URL-Mustern entsprechen. In diesem Fall weist content_scripts
den Browser an, ein Skript namens "page-eater.js" in alle Seiten unter https://developer.mozilla.org/ zu laden.
Hinweis:
Da die "js"
-Eigenschaft von content_scripts
ein Array ist, können Sie es verwenden, um mehr als ein Skript in passende Seiten zu injizieren. Wenn Sie dies tun, teilen die Seiten denselben Gültigkeitsbereich, genauso wie mehrere Skripte, die von einer Seite geladen werden, und sie werden in der Reihenfolge geladen, in der sie im Array aufgelistet sind.
Hinweis:
Der Schlüssel content_scripts
hat auch eine "css"
-Eigenschaft, mit der Sie CSS-Stylesheets injizieren können.
Erstellen Sie als Nächstes eine Datei namens "page-eater.js" im Verzeichnis "modify-page" und geben Sie ihr den folgenden Inhalt:
document.body.textContent = "";
let header = document.createElement("h1");
header.textContent = "This page has been eaten";
document.body.appendChild(header);
Installieren Sie nun die Erweiterung, und besuchen Sie https://developer.mozilla.org/. Die Seite sollte so aussehen:
Seiten programmgesteuert modifizieren
Was ist, wenn Sie die Seiten nur "verschlingen" wollen, wenn der Benutzer Sie darum bittet? Lassen Sie uns dieses Beispiel aktualisieren, sodass wir das Content-Skript injizieren, wenn der Benutzer auf einen Kontextmenüeintrag klickt.
Ändern Sie zunächst "manifest.json" so, dass es den folgenden Inhalt hat:
{
"manifest_version": 2,
"name": "modify-page",
"version": "1.0",
"permissions": ["activeTab", "contextMenus"],
"background": {
"scripts": ["background.js"]
}
}
Hier haben wir den Schlüssel content_scripts
entfernt und zwei neue Schlüssel hinzugefügt:
permissions
: Um Skripte in Seiten zu injizieren, benötigen wir Berechtigungen für die Seite, die wir modifizieren. DieactiveTab
Berechtigung ist eine Möglichkeit, diese temporär für den derzeit aktiven Tab zu erhalten. Wir benötigen außerdem die BerechtigungcontextMenus
, um Kontextmenüeinträge hinzufügen zu können.background
: Wir verwenden dies, um ein persistentes "Hintergrundskript" namensbackground.js
zu laden, in dem wir das Kontextmenü einrichten und das Content-Skript injizieren werden.
Erstellen Sie nun diese Datei. Erstellen Sie eine neue Datei namens background.js
im Verzeichnis modify-page
und geben Sie ihr den folgenden Inhalt:
browser.contextMenus.create({
id: "eat-page",
title: "Eat this page",
});
browser.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "eat-page") {
browser.tabs.executeScript({
file: "page-eater.js",
});
}
});
In diesem Skript erstellen wir einen Kontextmenüeintrag, geben ihm eine spezifische ID und einen Titel (der Text, der im Kontextmenü angezeigt wird). Dann richten wir einen Ereignislistener ein, der prüft, ob es sich um unseren eat-page
Eintrag handelt, wenn der Benutzer einen Kontextmenüeintrag anklickt. Wenn dies der Fall ist, injizieren wir "page-eater.js" in den aktuellen Tab mithilfe der tabs.executeScript()
API. Diese API nimmt optional eine Tab-ID als Argument: Wir haben die Tab-ID weggelassen, was bedeutet, dass das Skript in den derzeit aktiven Tab injiziert wird.
An diesem Punkt sollte die Erweiterung so aussehen:
modify-page/ background.js manifest.json page-eater.js
Laden Sie jetzt die Erweiterung neu, öffnen Sie eine Seite (diesmal beliebige Seite), aktivieren Sie das Kontextmenü und wählen Sie "Eat this page":
Nachrichtenübermittlung
Content-Skripte und Hintergrundskripte können nicht direkt auf den Zustand des jeweils anderen zugreifen. Sie können jedoch kommunizieren, indem sie Nachrichten senden. Ein Ende richtet einen Nachrichtenlistener ein, und das andere Ende kann ihm dann eine Nachricht senden. Die folgende Tabelle fasst die auf jeder Seite beteiligten APIs zusammen:
Im Content-Skript | Im Hintergrundskript | |
---|---|---|
Eine Nachricht senden |
browser.runtime.sendMessage()
|
browser.tabs.sendMessage()
|
Eine Nachricht empfangen |
browser.runtime.onMessage
|
browser.runtime.onMessage
|
Hinweis: Zusätzlich zu dieser Kommunikationsmethode, die Einzelnachrichten sendet, können Sie auch einen verbindungsbasierten Ansatz zum Nachrichtenversand verwenden. Für Ratschläge zur Auswahl zwischen den Optionen siehe Choosing between one-off messages and connection-based messaging.
Lassen Sie uns unser Beispiel aktualisieren, um zu zeigen, wie man eine Nachricht vom Hintergrundskript sendet.
Bearbeiten Sie zuerst background.js
, sodass es diesen Inhalt hat:
browser.contextMenus.create({
id: "eat-page",
title: "Eat this page",
});
function messageTab(tabs) {
browser.tabs.sendMessage(tabs[0].id, {
replacement: "Message from the extension!",
});
}
function onExecuted(result) {
let querying = browser.tabs.query({
active: true,
currentWindow: true,
});
querying.then(messageTab);
}
browser.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "eat-page") {
let executing = browser.tabs.executeScript({
file: "page-eater.js",
});
executing.then(onExecuted);
}
});
Nun, nach dem Injektieren von page-eater.js
, verwenden wir tabs.query()
, um den derzeit aktiven Tab zu erhalten, und verwenden dann tabs.sendMessage()
, um eine Nachricht an die Content-Skripte zu senden, die in diesen Tab geladen sind. Die Nachricht hat die Nutzlast {replacement: "Message from the extension!"}
.
Aktualisieren Sie als nächstes page-eater.js
wie folgt:
function eatPageReceiver(request, sender, sendResponse) {
document.body.textContent = "";
let header = document.createElement("h1");
header.textContent = request.replacement;
document.body.appendChild(header);
}
browser.runtime.onMessage.addListener(eatPageReceiver);
Anstatt die Seite sofort zu verschlingen, wartet das Content-Skript nun auf eine Nachricht über runtime.onMessage
. Wenn eine Nachricht eintrifft, führt das Content-Skript im Wesentlichen denselben Code wie zuvor aus, außer dass der Ersetzungstext von request.replacement
stammt.
Da tabs.executeScript()
eine asynchrone Funktion ist, und um sicherzustellen, dass wir die Nachricht nur senden, nachdem der Listener in page-eater.js
hinzugefügt wurde, verwenden wir onExecuted()
, das aufgerufen wird, nachdem page-eater.js
ausgeführt wurde.
Hinweis:
Drücken Sie Ctrl+Shift+J (oder Cmd+Shift+J auf macOS) ODER web-ext run --bc
, um die Browser-Konsole zu öffnen, um console.log
im Hintergrundskript anzuzeigen.
Alternativ können Sie den Add-on-Debugger verwenden, mit dem Sie einen Haltepunkt setzen können. Es gibt derzeit keine Möglichkeit, den Add-on-Debugger direkt von web-ext zu starten.
Wenn wir Nachrichten vom Content-Skript an die Hintergrundseite zurücksenden möchten, würden wir runtime.sendMessage()
anstelle von tabs.sendMessage()
verwenden, z.B.:
browser.runtime.sendMessage({
title: "from page-eater.js",
});
Hinweis:
Diese Beispiele injizieren alle JavaScript; Sie können auch CSS programmgesteuert mit der Funktion tabs.insertCSS()
injizieren.
Mehr erfahren
-
content_scripts
Manifest-Schlüssel -
permissions
Manifest-Schlüssel -
Beispiele, die
content_scripts
verwenden: -
Beispiele, die
tabs.executeScript()
verwenden: