自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

想要復(fù)制圖像?Clipboard API 了解一下

開發(fā) 前端
本文帶領(lǐng)大家對異步的 Clipboard API 的一些學(xué)習(xí)和了解,希望能對你有所幫助。

[[358841]]

在寫了 這個 29.7 K 的剪貼板 JS 庫有點東西! 這篇文章之后,收到了小伙伴提的兩個問題:

1.clipboard.js 這個庫除了復(fù)制文字之外,能復(fù)制圖像么?

2.clipboard.js 這個庫依賴的 document.execCommand API 已被廢棄了,以后應(yīng)該怎么辦?


(圖片來源:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand)

接下來,本文將圍繞上述兩個問題展開,不過在看第一個問題之前,我們先來簡單介紹一下 剪貼板 📋。

  • 剪貼板(英語:clipboard),有時也稱剪切板、剪貼簿、剪貼本。它是一種軟件功能,通常由操作系統(tǒng)提供,作用是使用復(fù)制和粘貼操作短期存儲數(shù)據(jù)和在文檔或應(yīng)用程序間轉(zhuǎn)移數(shù)據(jù)。它是圖形用戶界面(GUI)環(huán)境中最常用的功能之一,通常實現(xiàn)為匿名、臨時的數(shù)據(jù)緩沖區(qū),可以被環(huán)境內(nèi)的大部分或所有程序使用編程接口訪問。—— 維基百科

通過以上的描述我們可以知道,剪貼板架起了一座橋梁,使得在各種應(yīng)用程序之間,傳遞和共享信息成為可能。然而美中不足的是,剪貼板只能保留一份數(shù)據(jù),每當(dāng)新的數(shù)據(jù)傳入,舊的便會被覆蓋。

了解完 剪貼板 📋 的概念和作用之后,我們馬上來看一下第一個問題:clipboard.js 這個庫除了復(fù)制文字之外,能復(fù)制圖像么?

一、clipboard.js 能否復(fù)制圖像?

clipboard.js 是一個用于將 文本 復(fù)制到剪貼板的 JS 庫。沒有使用 Flash,沒有使用任何框架,開啟 gzipped 壓縮后僅僅只有 3kb。


(圖片來源:https://clipboardjs.com/#example-text)

當(dāng)你看到 “A modern approach to copy text to clipboard” 這個描述,你是不是已經(jīng)知道答案了。那么實際的情況是怎樣呢?下面我們來動手驗證一下。在 這個 29.7 K 的剪貼板 JS 庫有點東西! 這篇文章中,阿寶哥介紹了在實例化 ClipboardJS 對象時,可以通過 options 對象的 target 屬性來設(shè)置復(fù)制的目標(biāo):

  1. // https://github.com/zenorocha/clipboard.js/blob/master/demo/function-target.html 
  2. let clipboard = new ClipboardJS('.btn', { 
  3.   target: function() { 
  4.     return document.querySelector('div'); 
  5.   } 
  6. }); 

利用 clipboard.js 的這個特性,我們可以定義以下 HTML 結(jié)構(gòu):

  1. <div id="container"
  2.    <img src="http://cdn.semlinker.com/abao.png" width="80" height="80"/> 
  3.    <p>大家好,我是阿寶哥</p> 
  4. </div> 
  5. <button class="btn">復(fù)制</button> 

 然后在實例化 ClipboardJS 對象時設(shè)置復(fù)制的目標(biāo)是 #container 元素:

  1. const clipboard = new ClipboardJS(".btn", { 
  2.   target: function () { 
  3.     return document.querySelector("#container"); 
  4.   } 
  5. }); 

之后,我們點擊頁面中的 復(fù)制 按鈕,對應(yīng)的效果如下圖所示:

 

觀察上圖可知,頁面中的圖像和文本都已經(jīng)被復(fù)制了。對于文本來說,大家應(yīng)該都很清楚。而對于圖像來說,到底復(fù)制了什么?我們又該如何獲取已復(fù)制的內(nèi)容呢?針對這個問題,我們可以利用 HTMLElement 對象上的 onpaste 屬性或者監(jiān)聽元素上的 paste 事件。

這里我們通過設(shè)置 document 對象的 onpaste 屬性,來打印一下粘貼事件對應(yīng)的事件對象:

  1. document.onpaste = function (e) { 
  2.   console.dir(e); 

當(dāng)我們點擊 復(fù)制 按鈕,然后在頁面執(zhí)行 粘貼 操作后,控制臺會打印出以下內(nèi)容:


通過上圖可知,在 ClipboardEvent 對象中含有一個 clipboardData 屬性,該屬性包含了與剪貼板相關(guān)聯(lián)的數(shù)據(jù)。詳細(xì)分析了 clipboardData 屬性之后,我們發(fā)現(xiàn)已復(fù)制的圖像和普通文本被封裝為 DataTransferItem 對象。

為了更方便地分析 DataTransferItem 對象,阿寶哥重新更新了 document 對象的 onpaste屬性:


在上圖中,我們可以清楚的看到 DataTransferItem 對象上含有 kind 和 type 屬性分別用于表示數(shù)據(jù)項的類型(string 或 file)及數(shù)據(jù)對應(yīng)的 MIME 類型。利用 DataTransferItem 對象提供的 getAsString 方法,我們可以獲取該對象中保存的數(shù)據(jù):


相信看完以上的輸出結(jié)果,小伙伴們就很清楚第一個問題的答案了。那么如果想要復(fù)制圖像的話,應(yīng)該如何實現(xiàn)呢?其實這個問題的答案與小伙伴提的第二個問題的答案是一樣的,我們可以利用 Clipboard API 來實現(xiàn)復(fù)制圖像的問題及解決 document.execCommand API 已被廢棄的問題。

接下來,我們的目標(biāo)就是實現(xiàn)復(fù)制圖像的功能了,因為要利用到 Clipboard API,所以阿寶哥先來介紹一下該 API。

二、Clipboard API 簡介

Clipboard 接口實現(xiàn)了 Clipboard API,如果用戶授予了相應(yīng)的權(quán)限,就能提供系統(tǒng)剪貼板的讀寫訪問。在 Web 應(yīng)用程序中,Clipboard API 可用于實現(xiàn)剪切、復(fù)制和粘貼功能。該 API 用于取代通過 document.execCommand API 來實現(xiàn)剪貼板的操作。

在實際項目中,我們不需要手動創(chuàng)建 Clipboard 對象,而是通過 navigator.clipboard來獲取 Clipboard 對象:

 

在獲取 Clipboard 對象之后,我們就可以利用該對象提供的 API 來訪問剪貼板,比如:

  1. navigator.clipboard.readText().then
  2.   clipText => document.querySelector(".editor").innerText = clipText); 

以上代碼將 HTML 中含有 .editor 類的第一個元素的內(nèi)容替換為剪貼板的內(nèi)容。如果剪貼板為空,或者不包含任何文本,則元素的內(nèi)容將被清空。這是因為在剪貼板為空或者不包含文本時,readText 方法會返回一個空字符串。

在繼續(xù)介紹 Clipboard API 之前,我們先來看一下 Navigator API: clipboard 的兼容性:


(圖片來源:https://caniuse.com/mdn-api_navigator_clipboard)

異步剪貼板 API 是一個相對較新的 API,瀏覽器仍在逐漸實現(xiàn)它。由于潛在的安全問題和技術(shù)復(fù)雜性,大多數(shù)瀏覽器正在逐步集成這個 API。對于瀏覽器擴展來說,你可以請求 clipboardRead 和 clipboardWrite 權(quán)限以使用 clipboard.readText() 和 clipboard.writeText()。

好的,接下來阿寶哥來演示一下如何使用 clipboard 對象提供的 API 來操作剪貼板,以下示例的運行環(huán)境是 Chrome 87.0.4280.88。

三、將數(shù)據(jù)寫入到剪貼板

3.1 writeText()

writeText 方法可以把指定的字符串寫入到系統(tǒng)的剪貼板中,調(diào)用該方法后會返回一個 Promise 對象:

  1. <button onclick="copyPageUrl()">拷貝當(dāng)前頁面地址</button> 
  2. <script> 
  3.    async function copyPageUrl() { 
  4.      try { 
  5.        await navigator.clipboard.writeText(location.href); 
  6.        console.log("頁面地址已經(jīng)被拷貝到剪貼板中"); 
  7.      } catch (err) { 
  8.        console.error("頁面地址拷貝失敗: ", err); 
  9.      } 
  10.   } 
  11. </script> 

對于上述代碼,當(dāng)用戶點擊 拷貝當(dāng)前頁面地址 按鈕時,將會把當(dāng)前的頁面地址拷貝到剪貼板中。

3.2 write()

write 方法除了支持文本數(shù)據(jù)之外,還支持將圖像數(shù)據(jù)寫入到剪貼板,調(diào)用該方法后會返回一個 Promise 對象。

  1. <button onclick="copyPageUrl()">拷貝當(dāng)前頁面地址</button> 
  2. <script> 
  3.    async function copyPageUrl() { 
  4.      const text = new Blob([location.href], {type: 'text/plain'}); 
  5.      try { 
  6.        await navigator.clipboard.write( 
  7.          new ClipboardItem({ 
  8.            "text/plain": text, 
  9.          }), 
  10.        ); 
  11.        console.log("頁面地址已經(jīng)被拷貝到剪貼板中"); 
  12.      } catch (err) { 
  13.        console.error("頁面地址拷貝失敗: ", err); 
  14.      } 
  15.   } 
  16. </script> 

在以上代碼中,我們先通過 Blob API 創(chuàng)建 Blob 對象,然后使用該 Blob 對象來構(gòu)造 ClipboardItem 對象,最后再通過 write 方法把數(shù)據(jù)寫入到剪貼板。介紹完如何將數(shù)據(jù)寫入到剪貼板,下面我們來介紹如何從剪貼板中讀取數(shù)據(jù)。

四、從剪貼板中讀取數(shù)據(jù)

4.1 readText()

readText 方法用于讀取剪貼板中的文本內(nèi)容,調(diào)用該方法后會返回一個 Promise 對象:

  1. <button onclick="getClipboardContents()">讀取剪貼板中的文本</button> 
  2. <script> 
  3.    async function getClipboardContents() { 
  4.      try { 
  5.        const text = await navigator.clipboard.readText(); 
  6.        console.log("已讀取剪貼板中的內(nèi)容:", text); 
  7.      } catch (err) { 
  8.        console.error("讀取剪貼板內(nèi)容失敗: ", err); 
  9.      } 
  10.    } 
  11. </script> 

對于上述代碼,當(dāng)用戶點擊 讀取剪貼板中的文本 按鈕時,如果當(dāng)前剪貼板含有文本內(nèi)容,則會讀取剪貼板中的文本內(nèi)容。

4.2 read()

read 方法除了支持讀取文本數(shù)據(jù)之外,還支持讀取剪貼板中的圖像數(shù)據(jù),調(diào)用該方法后會返回一個 Promise 對象:

  1. <button onclick="getClipboardContents()">讀取剪貼板中的內(nèi)容</button> 
  2. <script> 
  3. async function getClipboardContents() { 
  4.   try { 
  5.     const clipboardItems = await navigator.clipboard.read(); 
  6.     for (const clipboardItem of clipboardItems) { 
  7.       for (const type of clipboardItem.types) { 
  8.         const blob = await clipboardItem.getType(type); 
  9.         console.log("已讀取剪貼板中的內(nèi)容:", await blob.text()); 
  10.       } 
  11.     } 
  12.   } catch (err) { 
  13.       console.error("讀取剪貼板內(nèi)容失敗: ", err); 
  14.     } 
  15.   } 
  16. </script> 

對于上述代碼,當(dāng)用戶點擊 讀取剪貼板中的內(nèi)容 按鈕時,則會開始讀取剪貼板中的內(nèi)容。到這里 clipboard 對象中涉及的 4 個 API,阿寶哥都已經(jīng)介紹完了,最后我們來看一下如何實現(xiàn)復(fù)制圖像的功能。

五、實現(xiàn)復(fù)制圖像的功能

在最后的這個示例中,阿寶哥將跟大家一步步實現(xiàn)復(fù)制圖像的核心功能,除了復(fù)制圖像之外,還會同時支持復(fù)制文本。在看具體代碼前,我們先來看一下實際的效果:

在上圖對應(yīng)的網(wǎng)頁中,我們先點擊 復(fù)制 按鈕,則圖像和文本都會被選中。之后,我們在點擊 粘貼 按鈕,則控制臺會輸出從剪貼板中讀取的實際內(nèi)容。在分析具體的實現(xiàn)方式前,我們先來看一下對應(yīng)的頁面結(jié)構(gòu):

  1. <div id="container"
  2.    <img src="http://cdn.semlinker.com/abao.png" width="80" height="80" /> 
  3.    <p>大家好,我是阿寶哥</p> 
  4. </div> 
  5. <button onclick="writeDataToClipboard()">復(fù)制</button> 
  6. <button onclick="readDataFromClipboard()">粘貼</button> 

 上面的頁面結(jié)構(gòu)很簡單,下一步我們來逐步分析一下以上功能的實現(xiàn)過程。

5.1 請求剪貼板寫權(quán)限

默認(rèn)情況下,會為當(dāng)前的激活的頁面自動授予剪貼板的寫入權(quán)限。出于安全方面考慮,這里我們還是主動向用戶請求剪貼板的寫入權(quán)限:

  1. async function askWritePermission() { 
  2.   try { 
  3.     const { state } = await navigator.permissions.query({ 
  4.       name"clipboard-write"
  5.     }); 
  6.       return state === "granted"
  7.   } catch (error) { 
  8.       return false
  9.   } 

5.2 往剪貼板寫入圖像和普通文本數(shù)據(jù)

要往剪貼板寫入圖像數(shù)據(jù),我們就需要使用 navigator.clipboard 對象提供的 write 方法。如果要寫入圖像數(shù)據(jù),我們就需要獲取該圖像對應(yīng)的 Blob 對象,這里我們可以通過 fetch API 從網(wǎng)絡(luò)上獲取圖像對應(yīng)的響應(yīng)對象并把它轉(zhuǎn)化成 Blob 對象,具體實現(xiàn)方式如下:

  1. async function createImageBlob(url) { 
  2.   const response = await fetch(url); 
  3.   return await response.blob(); 

而對于普通文本來說,只需要使用前面介紹的 Blob API 就可以把普通文本轉(zhuǎn)換為 Blob 對象:

  1. function createTextBlob(text) { 
  2.   return new Blob([text], { type: "text/plain" }); 

在創(chuàng)建完圖像和普通文本對應(yīng)的 Blob 對象之后,我們就可以利用它們來創(chuàng)建 ClipboardItem 對象,然后再調(diào)用 write 方法把這些數(shù)據(jù)寫入到剪貼板中,對應(yīng)的代碼如下所示:

  1. async function writeDataToClipboard() { 
  2.   if (askWritePermission()) { 
  3.     if (navigator.clipboard && navigator.clipboard.write) { 
  4.         const textBlob = createTextBlob("大家好,我是阿寶哥"); 
  5.         const imageBlob = await createImageBlob( 
  6.           "http://cdn.semlinker.com/abao.png" 
  7.         ); 
  8.         try { 
  9.           const item = new ClipboardItem({ 
  10.             [textBlob.type]: textBlob, 
  11.             [imageBlob.type]: imageBlob, 
  12.           }); 
  13.           select(document.querySelector("#container")); 
  14.           await navigator.clipboard.write([item]); 
  15.           console.log("文本和圖像復(fù)制成功"); 
  16.         } catch (error) { 
  17.           console.error("文本和圖像復(fù)制失敗", error); 
  18.         } 
  19.       } 
  20.    } 

在以上代碼中,使用了一個 select 方法,該方法用于實現(xiàn)選擇的效果,對應(yīng)的代碼如下所示:

  1. function select(element) { 
  2.   const selection = window.getSelection(); 
  3.   const range = document.createRange(); 
  4.   range.selectNodeContents(element); 
  5.   selection.removeAllRanges(); 
  6.   selection.addRange(range); 

通過 writeDataToClipboard 方法,我們已經(jīng)把圖像和普通文本數(shù)據(jù)寫入剪貼板了。下面我們來使用 navigator.clipboard 對象提供的 read 方法,來讀取已寫入的數(shù)據(jù)。如果你需要讀取剪貼板的數(shù)據(jù),則需要向用戶請求 clipboard-read 權(quán)限。

5.3 請求剪貼板讀取權(quán)限

這里我們定義了一個 askReadPermission 函數(shù)來向用戶請求剪貼板讀取權(quán)限:

  1. async function askReadPermission() { 
  2.   try { 
  3.     const { state } = await navigator.permissions.query({ 
  4.       name"clipboard-read"
  5.     }); 
  6.     return state === "granted"
  7.   } catch (error) { 
  8.     return false
  9.   } 

當(dāng)調(diào)用 askReadPermission 方法后,將會向當(dāng)前用戶請求剪貼板讀取權(quán)限,對應(yīng)的效果如下圖所示:


5.4 讀取剪貼板中已寫入的數(shù)據(jù)

創(chuàng)建好 askReadPermission 函數(shù),我們就可以利用之前介紹的 navigator.clipboard.read 方法來讀取剪貼板的數(shù)據(jù)了:

  1. async function readDataFromClipboard() { 
  2.   if (askReadPermission()) { 
  3.     if (navigator.clipboard && navigator.clipboard.read) { 
  4.       try { 
  5.         const clipboardItems = await navigator.clipboard.read(); 
  6.         for (const clipboardItem of clipboardItems) { 
  7.           console.dir(clipboardItem); 
  8.           for (const type of clipboardItem.types) { 
  9.             const blob = await clipboardItem.getType(type); 
  10.             console.log("已讀取剪貼板中的內(nèi)容:", await blob.text()); 
  11.           } 
  12.         } 
  13.       } catch (err) { 
  14.          console.error("讀取剪貼板內(nèi)容失敗: ", err); 
  15.       } 
  16.      } 
  17.    } 

其實,除了點擊 粘貼 按鈕之外,我們還可以通過監(jiān)聽 paste 事件來讀取剪貼板中的數(shù)據(jù)。需要注意的是,如果當(dāng)前的瀏覽器不支持異步 Clipboard API,我們可以通過 clipboardData.getData 方法來讀取剪貼板中的文本數(shù)據(jù):

  1. document.addEventListener('paste', async (e) => { 
  2.   e.preventDefault(); 
  3.   let text; 
  4.   if (navigator.clipboard) { 
  5.     text = await navigator.clipboard.readText(); 
  6.   } else { 
  7.     text = e.clipboardData.getData('text/plain'); 
  8.   } 
  9.   console.log('已獲取的文本數(shù)據(jù): ', text); 
  10. }); 

而對于圖像數(shù)據(jù),則可以通過以下方式進行讀?。?/p>

  1. const IMAGE_MIME_REGEX = /^image\/(p?jpeg|gif|png)$/i; 
  2.  
  3. document.addEventListener("paste", async (e) => { 
  4.   e.preventDefault(); 
  5.   if (navigator.clipboard) { 
  6.     let clipboardItems = await navigator.clipboard.read(); 
  7.     for (const clipboardItem of clipboardItems) { 
  8.        for (const type of clipboardItem.types) { 
  9.          if (IMAGE_MIME_REGEX.test(type)) { 
  10.            const blob = await clipboardItem.getType(type); 
  11.            loadImage(blob); 
  12.            return
  13.          } 
  14.         } 
  15.      } 
  16.    } else { 
  17.        const items = e.clipboardData.items; 
  18.        for (let i = 0; i < items.length; i++) { 
  19.          if (IMAGE_MIME_REGEX.test(items[i].type)) { 
  20.          loadImage(items[i].getAsFile()); 
  21.          return
  22.        } 
  23.     } 
  24.   } 
  25. }); 

以上代碼中的 loadImage 方法用于實現(xiàn)把復(fù)制的圖片插入到當(dāng)前選區(qū)已選擇的區(qū)域中,對應(yīng)的代碼如下:

  1. function loadImage(file) { 
  2.   const reader = new FileReader(); 
  3.   reader.onload = function (e) { 
  4.     let img = document.createElement("img"); 
  5.     img.src = e.target.result; 
  6.  
  7.     let range = window.getSelection().getRangeAt(0); 
  8.     range.deleteContents(); 
  9.     range.insertNode(img); 
  10.   }; 
  11.   reader.readAsDataURL(file); 

在前面代碼中,我們監(jiān)聽了 document 對象的 paste 事件。除了該事件之外,與剪貼板相關(guān)的常見事件還有 copy 和 cut 事件。篇幅有限,阿寶哥就不繼續(xù)展開介紹了,感興趣的小伙伴可以自行閱讀相關(guān)資料。

好的,至此本文就已經(jīng)結(jié)束了,希望閱讀完本文之后,大家對異步的 Clipboard API 會有些了解。

六、參考資源

  • 維基百科 - 剪貼板
  • MDN - Clipboard
  • MDN - execCommand
  • Web.dev - async-clipboard

 

責(zé)任編輯:姜華 來源: 全棧修仙之路
相關(guān)推薦

2020-12-10 08:44:35

WebSocket輪詢Comet

2022-03-24 13:36:18

Java悲觀鎖樂觀鎖

2019-02-20 14:16:43

2020-02-10 14:26:10

GitHub代碼倉庫

2018-06-05 17:40:36

人工智能語音識別

2024-04-11 12:19:01

Rust數(shù)據(jù)類型

2022-06-14 14:23:14

圖像存儲

2022-03-07 06:34:22

CQRS數(shù)據(jù)庫數(shù)據(jù)模型

2020-03-01 17:53:38

Excel大數(shù)據(jù)微軟

2018-07-17 14:42:50

2023-11-18 09:09:08

GNUBSD協(xié)議

2024-02-28 18:22:13

AI處理器

2023-08-21 11:24:43

AndroidCSS

2018-04-25 06:46:52

2023-06-30 07:22:48

新元素父節(jié)點編號

2021-01-21 10:23:43

數(shù)據(jù)庫架構(gòu)技術(shù)

2024-08-22 12:31:05

2018-04-12 17:29:43

眾籌Linux紅旗軟件

2019-03-11 14:33:21

Redis內(nèi)存模型數(shù)據(jù)庫

2024-04-26 08:41:04

ViteHMR項目
點贊
收藏

51CTO技術(shù)棧公眾號