JavaScript實(shí)現(xiàn)復(fù)制圖片功能的方法示例
最近開(kāi)發(fā)中遇到一個(gè)需求,就是用戶希望能通過(guò)直接點(diǎn)擊按鈕復(fù)制圖片,然后就可以很方便的把圖片發(fā)送到班群中,于是就有了復(fù)制圖片的需求。
那么如何通過(guò)JavaScript
來(lái)實(shí)現(xiàn)復(fù)制圖片呢?
一、前置知識(shí):如何實(shí)現(xiàn)復(fù)制?
既然要復(fù)制圖片,那我們先看看前端是怎么實(shí)現(xiàn)復(fù)制功能的。
一般來(lái)說(shuō),實(shí)現(xiàn)復(fù)制有2種方案:
document.execCommand()
方法;Clipboard API
;
復(fù)制功能的安全限制:復(fù)制腳本需要放在監(jiān)聽(tīng)事件回調(diào)里面進(jìn)行執(zhí)行,由用戶觸發(fā)(比如點(diǎn)擊事件),如果直接執(zhí)行腳本,瀏覽器可能會(huì)報(bào)錯(cuò)。
下面分別介紹下這2個(gè)方法:
1.1 document.execCommand()
使用方法:
先選中文本,然后調(diào)用 document.execCommand('copy')
,即可將選中的文本復(fù)制到剪貼板。
const input = document.getElementById("input"); input.select(); // 注意 input 框不能添加 disabled 屬性,否則會(huì)影響 select() 方法 document.execCommand("copy");
同樣的它還可以實(shí)現(xiàn)剪切
和粘貼
功能。
document.execCommand('cut')
:剪切選中的文本到剪貼板。document.execCommand('paste')
:從剪貼板粘貼文本到光標(biāo)位置。
剪切功能的使用和復(fù)制一樣,所以這里就不做演示了。我這邊再演示一下粘貼功能。
粘貼功能有以下使用限制:
- 確保元素是可編輯的,比如
input
、textarea
、contenteditable
屬性為true
的元素。 - 確保元素是焦點(diǎn)元素,可以使用
focus()
方法將焦點(diǎn)設(shè)置到元素上。
const target = document.getElementById('pasteTargetInput'); target.focus(); // 確保目標(biāo)元素獲得焦點(diǎn) document.execCommand('paste'); // 嘗試粘貼
但是現(xiàn)代瀏覽器比如(Chrome、Firefox、Edge
)已經(jīng)限制或廢棄了 execCommand("paste")
的直接使用,所以不推薦用這個(gè)api了。
最后總結(jié)一下,document.execCommand()
是實(shí)現(xiàn)復(fù)制的一個(gè)傳統(tǒng)方法,它的優(yōu)缺點(diǎn)如下:
- 優(yōu)點(diǎn):低版本瀏覽器兼容性好,
- 缺點(diǎn):
- 已被
web 標(biāo)準(zhǔn)
棄用,不推薦使用。 - 只能復(fù)制文本,不能復(fù)制圖片或者二進(jìn)制數(shù)據(jù)。
- 只能講選中的內(nèi)容寫入到剪貼板,不能直接寫入自定義內(nèi)容。
- 它是同步操作,如果復(fù)制內(nèi)容過(guò)多,會(huì)引起頁(yè)面卡頓。
1.2 Clipboard API
在瀏覽器的BOM
對(duì)象中,有一個(gè)API
叫clipboard
,它提供了系統(tǒng)剪貼板的讀寫訪問(wèn)能力,可以實(shí)現(xiàn)剪切、復(fù)制和粘貼功能
,我們可以通過(guò)window
上的navigator
對(duì)象直接訪問(wèn)到一個(gè)clipboard
對(duì)象。
console.log(navigator.clipboard);
clipboard
提供了四個(gè)方法:
read()
:從剪切板讀取數(shù)據(jù),它會(huì)返回一個(gè)Promise
,并將數(shù)據(jù)包裝成一個(gè)ClipboardItem
對(duì)象回傳,readText()
:從剪切板中讀取文本
,它會(huì)返回一個(gè)Promise
對(duì)象,并將剪切板數(shù)據(jù)作為String
回傳,write()
:寫入數(shù)據(jù)(ClipboardItem對(duì)象
)到剪切板,它會(huì)返回一個(gè)Promise
,Promise
成功意味著寫入完成,writeText()
:寫入文本
到剪切板,它會(huì)返回一個(gè)Promise
,Promise
成功意味著寫入完成。
我們可以通過(guò)上面描述的write()
和writeText()
方法實(shí)現(xiàn)復(fù)制功能,writeText()
只能寫入文本,而write()
方法則可以寫入任意數(shù)據(jù),所以我們需要使用write()
方法實(shí)現(xiàn)復(fù)制圖片的功能。
二、實(shí)現(xiàn)復(fù)制圖片
一般圖片是通過(guò)兩種形式加載:
- 遠(yuǎn)程URL,最常見(jiàn)的是
cdn
地址,比如https://cdn.xxx.cn/example.png
, - base64 URL,一些體積較小的圖片通常會(huì)打包成
base64
字符串,以減少網(wǎng)站資源請(qǐng)求數(shù)量,比如data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
。
不管是什么圖片形式的圖片,我們最終目的都是需要將它轉(zhuǎn)化為blob
對(duì)象,然后通過(guò)navigator.clipboard.write()
方法寫入到剪貼板。
比如這樣一張圖片:
<img src="https://xxx" alt="加載失敗" id="img"/>
我們可以通過(guò) canvas
將圖片復(fù)制到剪貼板,具體代碼如下:
function copyImage(img) { const canvas = document.createElement('canvas') canvas.width = img.width canvas.height = img.height const ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0, img.width, img.height) canvas.toBlob((blob) => { // 目前圖片只支持 png 類型 const clipboardItem = new ClipboardItem({ 'image/png': blob }) navigator.clipboard.write([clipboardItem]) }) } img.addEventListener("click", () => { copyImage(img); });
這里如果出現(xiàn)Uncaught SecurityError: Failed to execute 'toBlob' on 'HTMLCanvasElement'
報(bào)錯(cuò),可能是你使用的圖片跨域了,首先確保圖片資源服務(wù)器允許跨域使用,然后需要在img
標(biāo)簽上增加crossOrigin
屬性。
<img src="xxx" crossOrigin/>
當(dāng)然實(shí)際業(yè)務(wù)中可能提供的只是一個(gè)圖片點(diǎn)擊后的跳轉(zhuǎn)鏈接,需要先把鏈接轉(zhuǎn)成一張二維碼圖片,再進(jìn)行復(fù)制。
這里使用第三方庫(kù)qrcode
,把鏈接轉(zhuǎn)化成二維碼。
import QRcode from 'qrcode'; async function copyImage(url) { // 轉(zhuǎn)成 base64 的 url const url = await QRcode.toDataURL(link, { errorCorrectionLevel: 'H', // 糾錯(cuò)級(jí)別最高 width: 128, margin: 2, scale: 1, }); const blob = await (await fetch(url)).blob(); const clipboardItem = new ClipboardItem({ 'image/png': blob }) navigator.clipboard.write([clipboardItem]) }
我們這里通過(guò)QRcode.toDataURL()
方法,拿到二維碼的base64
圖片url,然后通過(guò)原生的fetch
方法,把二維碼圖片轉(zhuǎn)化成blob
對(duì)象,最后以ClipboardItem
形式寫入到clipboard
中。
除了fetch
以外,還可以通過(guò)如下方式將base64
圖片轉(zhuǎn)化為blob
對(duì)象,具體代碼如下:
function dataURIToBlob(dataURI) { const base64Index = dataURI.indexOf(';base64,') + 8; const base64 = dataURI.substring(base64Index); const byteCharacters = atob(base64); const byteArrays = []; for (let i = 0; i < byteCharacters.length; i++) { byteArrays.push(byteCharacters.charCodeAt(i)); } const byteArray = new Uint8Array(byteArrays); const blob = new Blob([byteArray], { type: 'image/png' }); return blob; }
三、clipboard兼容性問(wèn)題
在一些瀏覽器上可能不支持Clipboard API
,所以需要通過(guò)navigator.clipboard
的值是否為undefined
判斷此瀏覽器是否支持復(fù)制功能,如果不支持Clipboard API
的話,就無(wú)法復(fù)制圖片了,這時(shí)候可以使用document.execCommand('copy')
來(lái)復(fù)制文本,或者直接給用戶提示該瀏覽器不支持復(fù)制圖片。
// 將dataBase64復(fù)制到剪切板 function copyToClipboard(text) { let a = document.createElement('input'); a.value = text; document.body.appendChild(a); a.select(); document.execCommand('copy'); a.remove(); } function copyImage() { if (navigator.clipboard) { //... const clipboardItem = new ClipboardItem({ 'image/png': imgBlob }); navigator.clipboard.write([clipboardItem]); console.log('復(fù)制成功'); } else { copyToClipboard(img.src); } }
四、其它功能
4.1 預(yù)覽圖片
預(yù)覽圖片主要依賴于URL.createObjectURL
這個(gè)原生API
,具體代碼如下:
function previewImage(img) { const url = URL.createObjectURL(blob); const img = document.createElement('img'); img.src = url; document.body.appendChild(img); }
4.2 下載圖片
下載圖片主要依賴于a
標(biāo)簽的download
屬性,具體代碼如下:
function downloadImage(img) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = true; a.click(); URL.revokeObjectURL(url); console.log('下載圖片成功'); }
五、小結(jié)
本文主要介紹了前端如何實(shí)現(xiàn)復(fù)制圖片
的功能,核心是通過(guò)Clipboard API
來(lái)實(shí)現(xiàn)的,如遇到瀏覽器兼容問(wèn)題,可以考慮回退使用document.execCommand()
進(jìn)行低版本的兼容,另外還介紹了預(yù)覽圖片
和下載圖片
的實(shí)現(xiàn)思路,希望能幫助到大家!
以上就是JavaScript實(shí)現(xiàn)復(fù)制圖片功能的方法示例的詳細(xì)內(nèi)容,更多關(guān)于JavaScript復(fù)制圖片功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
理運(yùn)用命名空間讓js不產(chǎn)生沖突避免全局變量的泛濫
為了避免變量之間的覆蓋與沖突,可以生成命名空間,命名空間是一種特殊的前綴,在不同的匿名函數(shù)中,根據(jù)功能聲明一個(gè)不同的命名空間2014-06-06超強(qiáng)推薦的js編程中的簡(jiǎn)潔寫法收集
超強(qiáng)推薦的js編程中的簡(jiǎn)潔寫法收集...2007-08-08Bootstrap開(kāi)發(fā)實(shí)戰(zhàn)之第一次接觸Bootstrap
Bootstrap開(kāi)發(fā)實(shí)戰(zhàn)之第一次接觸Bootstrap,想要學(xué)好一門語(yǔ)言,首先應(yīng)該進(jìn)行深入了解,感興趣的小伙伴們可以參考一下2016-06-06javascript實(shí)現(xiàn)掃雷簡(jiǎn)易版
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)掃雷簡(jiǎn)易版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08JavaScript獲取移動(dòng)設(shè)備型號(hào)的實(shí)現(xiàn)代碼(JS獲取手機(jī)型號(hào)和系統(tǒng))
這篇文章主要介紹了JavaScript獲取移動(dòng)設(shè)備型號(hào)的實(shí)現(xiàn)代碼,需要的朋友可以參考下2018-03-03js canvas實(shí)現(xiàn)隨機(jī)粒子特效
這篇文章主要為大家詳細(xì)介紹了js canvas隨機(jī)粒子特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04