Sichererer Zugriff auf die Zwischenablage für Texte und Bilder
Der Zugriff auf die Systemzwischenablage erfolgte üblicherweise über
document.execCommand()
für Interaktionen in der Zwischenablage. Obwohl diese Methode des Schneidens und
Das Einfügen von Inhalten war kostenpflichtig: Der Zugriff auf die Zwischenablage erfolgte synchron und konnte nur
und in das DOM schreiben.
Das ist für kurze Textabschnitte in Ordnung, aber es gibt viele Fälle, in denen das Blockieren
für die Übertragung in die Zwischenablage ist keine gute Nutzererfahrung. Zeitaufwendige Bereinigungen oder
Möglicherweise ist eine Bilddecodierung erforderlich, bevor Inhalte sicher eingefügt werden können. Der Browser
müssen möglicherweise verknüpfte Ressourcen aus einem eingefügten Dokument laden oder inline einfügen. Das würde
die Seite während des Wartens auf dem Laufwerk oder Netzwerk blockieren. Berechtigungen hinzufügen
Der Browser muss die Seite während der Anfrage blockieren.
Zugriff auf die Zwischenablage. Gleichzeitig werden die Berechtigungen
document.execCommand()
für Interaktionen in der Zwischenablage sind lose definiert und variieren.
zwischen Browsern.
Die Async Clipboard API Probleme behoben und ein klar definiertes Berechtigungsmodell bereitgestellt wird, um die Seite zu blockieren. Die Async Clipboard API ist auf die Verarbeitung von Text und Bildern beschränkt. in den meisten Browsern. Die Unterstützung variiert jedoch. Browser genau analysieren Kompatibilitätsübersicht für jeden der folgenden Abschnitte.
Kopieren: Daten in die Zwischenablage schreiben
writeText()
Rufe writeText()
auf, um Text in die Zwischenablage zu kopieren. Da diese API
asynchron ist, gibt die Funktion writeText()
ein Versprechen zurück, das die
werden abgelehnt, je nachdem, ob der übergebene Text kopiert wurde:
async function copyPageUrl() {
try {
await navigator.clipboard.writeText(location.href);
console.log('Page URL copied to clipboard');
} catch (err) {
console.error('Failed to copy: ', err);
}
}
write()
writeText()
ist im Grunde nur eine bequeme Methode für die generische write()
.
, mit der Sie auch Bilder in die Zwischenablage kopieren können. Wie bei writeText()
gibt es auch
ist asynchron und gibt ein Versprechen zurück.
Um ein Bild in die Zwischenablage zu schreiben, benötigen Sie das Bild als
blob
Eine Möglichkeit,
fordern Sie das Image mithilfe von fetch()
von einem Server an und rufen Sie dann
blob()
im
Antwort.
Für einen Nutzer ist es möglicherweise nicht wünschenswert oder möglich, ein Bild vom Server anzufordern.
aus verschiedenen Gründen. Glücklicherweise können Sie das Bild auch auf einen Canvas zeichnen
Canvas aufrufen“
toBlob()
.
Übergeben Sie als Nächstes ein Array von ClipboardItem
-Objekten als Parameter an die write()
. Derzeit können Sie nur jeweils ein Bild übergeben. Wir hoffen jedoch,
in Zukunft mehrere Bilder unterstützt. ClipboardItem
verwendet ein Objekt mit
Der MIME-Typ des Bildes als Schlüssel und das Blob als Wert. Für Blob
Objekte, die aus fetch()
oder canvas.toBlob()
abgerufen wurden, dem Attribut blob.type
enthält automatisch den richtigen MIME-Typ für ein Bild.
try {
const imgURL = '/images/generic/file.png';
const data = await fetch(imgURL);
const blob = await data.blob();
await navigator.clipboard.write([
new ClipboardItem({
// The key is determined dynamically based on the blob's type.
[blob.type]: blob
})
]);
console.log('Image copied.');
} catch (err) {
console.error(err.name, err.message);
}
Alternativ kannst du ein Promise in das ClipboardItem
-Objekt schreiben.
Für dieses Muster müssen Sie den MIME-Typ der Daten im Voraus kennen.
try {
const imgURL = '/images/generic/file.png';
await navigator.clipboard.write([
new ClipboardItem({
// Set the key beforehand and write a promise as the value.
'image/png': fetch(imgURL).then(response => response.blob()),
})
]);
console.log('Image copied.');
} catch (err) {
console.error(err.name, err.message);
}
Das Kopierereignis
Wenn ein Nutzer das Kopieren in die Zwischenablage startet
und ruft nicht preventDefault()
auf, der
copy
-Ereignis
enthält eine clipboardData
-Eigenschaft mit den Elementen, die bereits das richtige Format haben.
Wenn Sie Ihre eigene Logik implementieren möchten, müssen Sie preventDefault()
aufrufen,
das Standardverhalten zugunsten Ihrer eigenen Implementierung verhindern.
In diesem Fall ist clipboardData
leer.
Nehmen wir einmal eine Seite mit Text und einem Bild.
Wenn die Nutzenden alle und
ein Kopieren in die Zwischenablage initiiert, sollte Ihre benutzerdefinierte Lösung Text verwerfen und nur
kopieren Sie das Bild. Sie können dies wie im Codebeispiel unten gezeigt erreichen.
In diesem Beispiel wird nicht behandelt, wie auf das vorherige
APIs, wenn die Clipboard API nicht unterstützt wird
<!-- The image we want on the clipboard. -->
<img src="kitten.webp" alt="Cute kitten.">
<!-- Some text we're not interested in. -->
<p>Lorem ipsum</p>
document.addEventListener("copy", async (e) => {
// Prevent the default behavior.
e.preventDefault();
try {
// Prepare an array for the clipboard items.
let clipboardItems = [];
// Assume `blob` is the blob representation of `kitten.webp`.
clipboardItems.push(
new ClipboardItem({
[blob.type]: blob,
})
);
await navigator.clipboard.write(clipboardItems);
console.log("Image copied, text ignored.");
} catch (err) {
console.error(err.name, err.message);
}
});
Für das copy
-Ereignis:
Für ClipboardItem
:
Einfügen: Daten werden aus der Zwischenablage gelesen.
readText()
Um Text aus der Zwischenablage vorzulesen, rufe navigator.clipboard.readText()
auf und warte
bis das zurückgegebene Promise aufgelöst wird:
async function getClipboardContents() {
try {
const text = await navigator.clipboard.readText();
console.log('Pasted content: ', text);
} catch (err) {
console.error('Failed to read clipboard contents: ', err);
}
}
read()
Die Methode navigator.clipboard.read()
ist ebenfalls asynchron und gibt ein
versprochen. Um ein Bild aus der Zwischenablage zu lesen, rufen Sie eine Liste mit
ClipboardItem
und dann iterieren.
Jede ClipboardItem
kann ihren Inhalt in verschiedenen Typen enthalten. Deshalb müssen Sie
iterieren Sie über die Liste der Typen, wieder mit einer for...of
-Schleife. Für jeden Typ
Rufen Sie die Methode getType()
mit dem aktuellen Typ als Argument auf, um die Methode
entsprechenden Blob. Wie zuvor ist dieser Code nicht an Bilder gebunden.
zukünftige Dateitypen verwenden können.
async function getClipboardContents() {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
console.log(URL.createObjectURL(blob));
}
}
} catch (err) {
console.error(err.name, err.message);
}
}
Mit eingefügten Dateien arbeiten
Es ist hilfreich für Nutzende, wenn sie Tastenkombinationen für die Zwischenablage verwenden können, z. B. Strg + C und Strg + V. Chromium zeigt schreibgeschützt Dateien in der Zwischenablage an, wie unten beschrieben. Diese Option wird ausgelöst, wenn der Nutzer die standardmäßige Tastenkombination zum Einfügen des Betriebssystems verwendet oder wenn der Nutzer in der Menüleiste des Browsers auf Bearbeiten und dann auf Einfügen klickt. Es ist kein weiterer Klempnercode erforderlich.
document.addEventListener("paste", async e => {
e.preventDefault();
if (!e.clipboardData.files.length) {
return;
}
const file = e.clipboardData.files[0];
// Read the file's contents, assuming it's a text file.
// There is no way to write back to it.
console.log(await file.text());
});
Ereignis „Einfügen“
Wie bereits erwähnt, gibt es Pläne, Ereignisse einzuführen, die mit der Clipboard API funktionieren,
aber vorerst können Sie das vorhandene paste
-Ereignis verwenden. Funktioniert problemlos mit dem neuen
asynchrone Methoden zum Lesen von Text in der Zwischenablage. Wie beim copy
-Ereignis sollten Sie
vergessen, preventDefault()
anzurufen.
document.addEventListener('paste', async (e) => {
e.preventDefault();
const text = await navigator.clipboard.readText();
console.log('Pasted text: ', text);
});
Mehrere MIME-Typen verarbeiten
Bei den meisten Implementierungen werden für einen einzelnen Schnitt mehrere Datenformate in die Zwischenablage eingefügt. oder einen Kopiervorgang ausführen. Dafür gibt es zwei Gründe: Als App-Entwickler die Funktionen der App nicht kennen, in die Nutzende Text oder Bilder kopieren möchten, und viele Anwendungen unterstützen das Einfügen strukturierter Daten als Nur-Text. Das ist normalerweise Der Menüpunkt Bearbeiten mit einem Namen wie Einfügen und Übereinstimmungsstil oder Ohne Formatierung einfügen aus.
Das folgende Beispiel zeigt, wie das geht. In diesem Beispiel wird mit fetch()
Folgendes ermittelt:
Bilddaten stammen, kann aber auch
<canvas>
oder die File System Access API verwenden.
async function copy() {
const image = await fetch('kitten.png').then(response => response.blob());
const text = new Blob(['Cute sleeping kitten'], {type: 'text/plain'});
const item = new ClipboardItem({
'text/plain': text,
'image/png': image
});
await navigator.clipboard.write([item]);
}
Sicherheit und Berechtigungen
Der Zugriff auf die Zwischenablage stellt für Browser schon immer ein Sicherheitsproblem dar. Ohne
Berechtigungen erteilt, könnte eine Seite unbemerkt alle Arten schädlicher Inhalte kopieren
in die Zwischenablage einfügen,
die nach dem Einfügen katastrophale Folgen haben würden.
Angenommen, eine Webseite kopiert automatisch rm -rf /
oder einen
Dekomprimierungsbombenbild
in die Zwischenablage.
Noch mehr Möglichkeiten, Webseiten uneingeschränkten Lesezugriff auf die Zwischenablage zu gewähren ärgerlich. Nutzer kopieren routinemäßig vertrauliche Informationen wie Passwörter und persönlichen Daten in die Zwischenablage legen, die dann von jeder Seite gelesen werden können, Wissen der Nutzenden.
Wie bei vielen neuen APIs wird die Clipboard API nur für Seiten unterstützt, die über HTTPS Um Missbrauch besser vorzubeugen, ist der Zugriff auf die Zwischenablage nur erlaubt, wenn eine Seite auf dem aktiven Tab. Seiten auf aktiven Tabs können in die Zwischenablage schreiben, ohne Berechtigung anfordern. Zum Lesen aus der Zwischenablage ist jedoch immer eine Berechtigung.
Berechtigungen zum Kopieren und Einfügen wurden hinzugefügt.
Permissions API verfügbar.
Die Berechtigung clipboard-write
wird Seiten automatisch gewährt, wenn
auf dem aktiven Tab. Sie müssen die Berechtigung clipboard-read
anfordern, die Sie
indem wir versuchen,
Daten aus der Zwischenablage zu lesen. Der folgende Code zeigt Letzteres:
const queryOpts = { name: 'clipboard-read', allowWithoutGesture: false };
const permissionStatus = await navigator.permissions.query(queryOpts);
// Will be 'granted', 'denied' or 'prompt':
console.log(permissionStatus.state);
// Listen for changes to the permission state
permissionStatus.onchange = () => {
console.log(permissionStatus.state);
};
Sie können auch festlegen, ob eine Nutzergeste zum Ausschneiden oder
mit der Option allowWithoutGesture
einfügen. Der Standardwert für diesen Wert
variiert je nach Browser, daher sollten Sie sie immer einbeziehen.
Hier kommt der asynchrone Charakter der Clipboard API besonders gut an: Beim Versuch, Daten aus der Zwischenablage zu lesen oder zu schreiben, wird der Nutzer automatisch aufgefordert, wenn sie nicht bereits gewährt wurde. Da die API versprechen-basiert ist, Dies ist vollkommen transparent und ein Nutzer, der die Berechtigung für die Zwischenablage ablehnt, das Versprechen abzulehnen, damit die Seite entsprechend reagieren kann.
Da Browser nur den Zugriff auf die Zwischenablage erlauben, wenn eine Seite der aktive Tab ist,
werden Sie feststellen, dass einige der Beispiele nicht funktionieren, wenn sie direkt in
die Konsole des Browsers, da die Entwicklertools
der aktive Tab sind. Es gibt einen Trick: das Verschieben
mit setTimeout()
auf die Zwischenablage zugreifen und dann schnell in die Seite klicken,
fokussieren Sie es, bevor die Funktionen aufgerufen werden:
setTimeout(async () => {
const text = await navigator.clipboard.readText();
console.log(text);
}, 2000);
Integration von Berechtigungsrichtlinien
Um die API in iFrames zu verwenden, müssen Sie sie mit
Berechtigungsrichtlinie
definiert einen Mechanismus, mit dem selektiv
Deaktivierung verschiedener Browserfunktionen und APIs Sie müssen entweder
oder sowohl clipboard-read
als auch clipboard-write
, abhängig von den Anforderungen Ihrer App.
<iframe
src="index.html"
allow="clipboard-read; clipboard-write"
>
</iframe>
Funktionserkennung
Um die Async Clipboard API zu verwenden und gleichzeitig alle Browser zu unterstützen, testen Sie
navigator.clipboard
und Fallback auf frühere Methoden. Hier sehen Sie zum Beispiel,
können Sie das Einfügen auch
für andere Browser implementieren.
document.addEventListener('paste', async (e) => {
e.preventDefault();
let text;
if (navigator.clipboard) {
text = await navigator.clipboard.readText();
}
else {
text = e.clipboardData.getData('text/plain');
}
console.log('Got pasted text: ', text);
});
Das ist nicht die ganze Geschichte. Vor der Async Clipboard API gab es eine Mischung aus
verschiedene Implementierungen für das Kopieren und Einfügen
bei verschiedenen Webbrowsern. In den meisten Browsern
kann das Kopieren und Einfügen des Browsers mit
document.execCommand('copy')
und document.execCommand('paste')
. Wenn der Text
eine Zeichenfolge ist, die nicht im DOM vorhanden ist, muss in das
DOM und ausgewählt:
button.addEventListener('click', (e) => {
const input = document.createElement('input');
input.style.display = 'none';
document.body.appendChild(input);
input.value = text;
input.focus();
input.select();
const result = document.execCommand('copy');
if (result === 'unsuccessful') {
console.error('Failed to copy text.');
}
input.remove();
});
Demos
In den Demos unten können Sie die Async Clipboard API ausprobieren. Bei Glitch You kann die Textdemo remixen oder die Bilddemo mit ihnen experimentieren.
Das erste Beispiel zeigt, wie Text in die Zwischenablage und aus der Zwischenablage verschoben wird.
Verwenden Sie diese Demo, um die API mit Bildern auszuprobieren. Denken Sie daran, dass nur PNGs unterstützt werden. und nur in in einigen Browsern.
Weitere Informationen
Danksagungen
Die Asynchronous Clipboard API wurde von Darwin implementiert, Huang und Gary Kačmarčík Darwin hat auch die Demo zur Verfügung gestellt. Vielen Dank an Kyarik und Gary Kačmarčík einige Teile dieses Artikels.
Hero-Image von Markus Winkler auf Unsplash (Unsplash).