前言
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 或者全域性 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。