BOM – Clipboard API
前言
Clipboard API 就是和 copy and paste 相关的 BOM API。
Copy Text
我们经常能看见这样的交互体验

点击 Copy code 以后,下面的代码就会被 copy 起来。
等同于我们 select 那些 code 之后按 ctrl + c。
这个就是用 Clipboard API 实现的。
<button class="copy-code-btn">Copy code</button>
const copyCodeBtn = document.querySelector('.copy-code-btn')!;
copyCodeBtn.addEventListener('click', async () => {
await window.navigator.clipboard.writeText(`console.log('hello world');`);
});
代码很简单,我就不解释了,直接看效果呗

Copy Image
除了 text 以外,想要 copy 图片也可以。
<button class="copy-image-btn">Copy image</button>
const copyImageBtn = document.querySelector('.copy-image-btn')!;
copyImageBtn.addEventListener('click', async () => {
// 1. fetch 一张图
const imageResponse = await fetch('/src/test-files/stooges-logo.png');
// 2. 获取图的 blob
const imageBlob = await imageResponse.blob();
// 3. 把 blob 装进 ClipboardItem
const clipboardItem = new ClipboardItem({ [imageBlob.type]: imageBlob });
// 4. 调用 write 方法,传入 ClipboardItem
await window.navigator.clipboard.write([clipboardItem]);
});
注1:图片必须是 png 格式,其它的格式不一定支持。
注2:只能传入一个 ClipboardItem,multiple 不一定支持。
效果

另外呢,blob 支持多种类型,比如 text/html
const htmlText = '<p>Hello, world!</p>'; const htmlTextBlob = new Blob([new TextEncoder().encode(htmlText)], { type: 'text/html', }); const htmlTextClipboardItem = new ClipboardItem({ [htmlTextBlob.type]: htmlTextBlob }); await window.navigator.clipboard.write([htmlTextClipboardItem]);
这样也是 ok 的。
Paste Text
能 copy 自然也能 paste。
<button class="paste-text-btn">Paste text</button>
const pasteTextBtn = document.querySelector('.paste-text-btn')!;
pasteTextBtn.addEventListener('click', async () => {
const text = await window.navigator.clipboard.readText();
console.log('paste: ', text);
});
调用 readText 方法就可以拿到当前 copy 着的 text 了。(注:游览器会先像用户获取权限)
效果

Paste with different types
copy 的内容不仅仅是 text,也可以是图片,或者 rich text (HTML string)。
我们可以透过 read 方法读取内容,接着判断类型,然后解析出不同的内容。
pasteTextBtn.addEventListener('click', async () => {
// 1. read items
const clipboardItems = await window.navigator.clipboard.read();
// 2. get first item (因为 Chrome 不支持 multiple,所以只会有 1 个 item)
const clipboardItem = clipboardItems[0];
// 3. 查看 item 的类型
// 它是一个 string array
// 假如是 html text,它会是 ['text/plain', 'text/html']
// 假如是 html 的图片,它会是 ['text/html', 'image/png']
console.log('types', clipboardItem.types);
// 4. 指定读取的类型,读出来是 blob,我们还需要 decode 成 string
const textDecoder = new TextDecoder();
console.log('plain text', textDecoder.decode(await (await clipboardItem.getType('text/plain')).arrayBuffer()));
console.log('html text', textDecoder.decode(await (await clipboardItem.getType('text/html')).arrayBuffer()));
});
效果

在网站 select text,最终的内容类型会是 ['text/plain', 'text/html']。

text/plain 返回的是 "Hello World" 单纯的 string。
text/html 返回的是 html string,还包括了样式。
再看看 paste image 的效果

console.log('image blob', await clipboardItem.getType('image/png'));

注:虽然图片本来是 jpeg 格式,但经过 copy paste 就变成了 png 格式,这是因为 Chrome 不支持 jpeg,只支持 png。
Copy & Paste Event
当用户在网站内 ctrl + c 或者 right click + copy 就会触发 'copy' 事件。(注:right click + copy image 在 Chrome 不会触发 copy 事件...不知道为什么🤔)
我们可以在某些 element (e.g. input, textarea, contenteditable) 或者全局 document 去监听这个事件 (copy 事件会冒泡)
document.addEventListener('copy', async (event: ClipboardEvent) => {
console.log(await window.navigator.clipboard.readText()); // 读取 copy 的内容
event.preventDefault(); // 阻止 copy 内容
await window.navigator.clipboard.writeText(`can't copy this!`); // 改写 copy 的内容
});
'paste' 事件也是如此
document.addEventListener('paste', async (event: ClipboardEvent) => {
console.log(await window.navigator.clipboard.readText()); // 读取 paste 的内容
event.preventDefault(); // 阻止 paste 内容
});
ClipboardEvent 没有什么鸟用,主要还是操作 Clipboard API。

浙公网安备 33010602011771号