Ändern einer Webseite
Ein häufiges Anwendungsbeispiel für eine Erweiterung ist das Ändern einer Webseite. Zum Beispiel könnte eine Erweiterung den Stil einer Seite ändern, bestimmte DOM-Knoten ausblenden oder zusätzliche DOM-Knoten in die Seite einfügen wollen.
Es gibt zwei Möglichkeiten, dies mit den WebExtensions-APIs zu tun:
- Deklarativ: Definieren Sie ein Muster, das auf eine Reihe von URLs zutrifft, und laden Sie eine Reihe von Skripten in Seiten, deren URL mit diesem Muster übereinstimmt.
- Programmgesteuert: Laden Sie ein Skript mit einer JavaScript-API in die Seite, 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 Messaging-API.
In diesem Artikel werden wir uns beide Methoden zum Laden eines Skripts ansehen.
Seiten ändern, die mit einem URL-Muster übereinstimmen
Erstellen Sie zunächst ein neues Verzeichnis mit dem Namen "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
ist die Methode, um Skripte in Seiten zu laden, die mit URL-Mustern übereinstimmen. 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 einzufügen. Wenn Sie dies tun, teilen sich die Seiten denselben Gültigkeitsbereich, genau 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
verfügt auch über eine "css"
-Eigenschaft, die Sie verwenden können, um CSS-Stylesheets einzufügen.
Erstellen Sie als nächstes eine Datei namens "page-eater.js" im Verzeichnis "modify-page" und geben Sie ihr 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 ändern
Was, wenn Sie Seiten nur dann "fressen" wollen, wenn der Benutzer Sie dazu auffordert? Aktualisieren wir dieses Beispiel so, dass wir das Content-Skript einfügen, wenn der Benutzer auf ein Kontextmenüelement klickt.
Aktualisieren Sie zuerst "manifest.json", sodass 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 einzufügen, benötigen wir Berechtigungen für die Seite, die wir ändern. Die BerechtigungactiveTab
ist eine Möglichkeit, diese vorübergehend für den aktuell aktiven Tab zu erhalten. Außerdem benötigen wir die BerechtigungcontextMenus
, um Kontextmenüelemente hinzufügen zu können.background
: Wir verwenden dies, um ein persistentes "Background-Skript" namensbackground.js
zu laden, in dem wir das Kontextmenü einrichten und das Content-Skript einfügen werden.
Lassen Sie uns diese Datei erstellen. 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 ein Kontextmenüelement, geben ihm eine spezifische ID und einen Titel (den Text, der im Kontextmenü angezeigt werden soll). Dann richten wir einen Event-Listener ein, sodass wir, wenn der Benutzer auf ein Kontextmenüelement klickt, überprüfen, ob es unser eat-page
-Element ist. Wenn dies der Fall ist, fügen wir "page-eater.js" in den aktuellen Tab mithilfe der API tabs.executeScript()
ein. Diese API benötigt optional eine Tab-ID als Argument: Da wir die Tab-ID weggelassen haben, wird das Skript in den aktuell aktiven Tab eingefügt.
An diesem Punkt sollte die Erweiterung so aussehen:
modify-page/ background.js manifest.json page-eater.js
Laden Sie jetzt die Erweiterung erneut, öffnen Sie eine Seite (diesmal jede beliebige Seite), aktivieren Sie das Kontextmenü und wählen Sie "Eat this page":
Messaging
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 Nachrichten-Listener 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 Einzelmitteilungen sendet, können Sie auch einen Verbindungsbasierten Ansatz zum Nachrichtenaustausch verwenden. Für Ratschläge zur Auswahl zwischen den Optionen siehe Auswahl zwischen Einzelmitteilungen und verbindungsbasierter Kommunikation.
Lassen Sie uns unser Beispiel aktualisieren, um zu zeigen, wie man eine Nachricht von dem 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 verwenden wir nach dem Einfügen von page-eater.js
tabs.query()
, um den aktuell aktiven Tab zu erhalten, und anschließend 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
folgendermaßen:
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);
Jetzt, anstatt die Seite sofort zu fressen, hört das Content-Skript auf eine Nachricht mittels runtime.onMessage
. Wenn eine Nachricht ankommt, führt das Content-Skript im Wesentlichen denselben Code wie zuvor aus, außer dass der Ersetzungstext von request.replacement
übernommen wird.
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 nach der Ausführung von page-eater.js
aufgerufen wird.
Hinweis:
Drücken Sie Strg+Umschalt+J (oder Befehl+Umschalt+J auf macOS) ODER web-ext run --bc
, um die Browser-Konsole zu öffnen und console.log
im Hintergrundskript anzuzeigen.
Alternativ können Sie den Add-on-Debugger verwenden, der es Ihnen ermöglicht, Haltepunkte festzulegen. Es gibt derzeit keine Möglichkeit, den Add-on-Debugger direkt über web-ext zu starten.
Wenn wir Nachrichten zurück vom Content-Skript zur Hintergrundseite senden wollen, 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()
einfügen.
Erfahren Sie mehr
-
Content-Skripte Leitfaden
-
content_scripts
Manifest-Schlüssel -
permissions
Manifest-Schlüssel -
Beispiele, die
content_scripts
verwenden: -
Beispiele, die
tabs.executeScript()
verwenden: