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)容寫(xiě)入到剪貼板,不能直接寫(xiě)入自定義內(nèi)容。
- 它是同步操作,如果復(fù)制內(nèi)容過(guò)多,會(huì)引起頁(yè)面卡頓。
1.2 Clipboard API
在瀏覽器的BOM對(duì)象中,有一個(gè)API叫clipboard,它提供了系統(tǒng)剪貼板的讀寫(xiě)訪問(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():寫(xiě)入數(shù)據(jù)(ClipboardItem對(duì)象)到剪切板,它會(huì)返回一個(gè)Promise,Promise成功意味著寫(xiě)入完成,writeText():寫(xiě)入文本到剪切板,它會(huì)返回一個(gè)Promise,Promise成功意味著寫(xiě)入完成。
我們可以通過(guò)上面描述的write()和writeText()方法實(shí)現(xiàn)復(fù)制功能,writeText()只能寫(xiě)入文本,而write()方法則可以寫(xiě)入任意數(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()方法寫(xiě)入到剪貼板。
比如這樣一張圖片:
<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形式寫(xiě)入到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)潔寫(xiě)法收集
超強(qiáng)推薦的js編程中的簡(jiǎn)潔寫(xiě)法收集...2007-08-08
Bootstrap開(kāi)發(fā)實(shí)戰(zhàn)之第一次接觸Bootstrap
Bootstrap開(kāi)發(fā)實(shí)戰(zhàn)之第一次接觸Bootstrap,想要學(xué)好一門(mén)語(yǔ)言,首先應(yīng)該進(jìn)行深入了解,感興趣的小伙伴們可以參考一下2016-06-06
javascript實(shí)現(xiàn)掃雷簡(jiǎn)易版
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)掃雷簡(jiǎn)易版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
JavaScript獲取移動(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-03
js canvas實(shí)現(xiàn)隨機(jī)粒子特效
這篇文章主要為大家詳細(xì)介紹了js canvas隨機(jī)粒子特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04

