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。

 

posted @ 2024-11-24 18:15  兴杰  阅读(18)  评论(0编辑  收藏  举报