JavaScript實(shí)現(xiàn)復(fù)制粘貼剪切功能三種方法
方式一:原生方式實(shí)現(xiàn)復(fù)制粘貼剪切(不推薦)
使用瀏覽器自帶的document.execCommand('copy')
實(shí)現(xiàn)復(fù)制,document.execCommand('paste')
實(shí)現(xiàn)粘貼,document.execCommand('cut')
實(shí)現(xiàn)剪切,這三個(gè)方法的返回值是布爾類型,用來判斷當(dāng)前瀏覽器中能夠使用這些方法,true表示方法能用,false表示方法不能用,目前因?yàn)?code>document.execCommand('paste')涉及到安全問題,考慮到安全原因, document.execCommand(‘paste’)操作已經(jīng)被禁止了。
補(bǔ)充說明下,目前官方已經(jīng)不推薦使用原生方式進(jìn)行復(fù)制粘貼操作了,這幾種方法隨時(shí)可能會(huì)被刪掉
代碼如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <input type="text" id="input" value="123" /> <button onclick="copy1()">復(fù)制(復(fù)制可編輯的標(biāo)簽中的內(nèi)容)</button> <button onclick="copy2('這是復(fù)制的內(nèi)容')">復(fù)制(將可編輯的標(biāo)簽隱藏)</button> <button onclick="cut()">剪切</button> <button onclick="paste()">粘貼</button> <input type="text" id="output"> <script> // 復(fù)制可編輯標(biāo)簽中的value值得內(nèi)容 function copy1() { const inputEle = document.querySelector("#input"); inputEle.select(); // 鼠標(biāo)選擇的內(nèi)容 document.execCommand("copy"); // 復(fù)制 } /** * 如果想使用 execCommand 方法,又不想頁(yè)面中出現(xiàn)可編輯區(qū)域,可以用下述辦法取巧 * @content 是要復(fù)制的內(nèi)容 */ function copy2(content) { const dom = document.createElement("input"); dom.value = content; document.body.appendChild(dom); dom.select(); document.execCommand("copy"); document.body.removeChild(dom); } // 剪切功能 function cut(){ console.log("cut"); document.execCommand("cut") } // 粘貼功能:注意,只會(huì)在光標(biāo)所在位置進(jìn)行粘貼 // function paste(){ // const pasteText = document.querySelector("#output") // pasteText.focus() // 讓光標(biāo)聚焦到output標(biāo)識(shí)的輸入框上 // document.execCommand("paste"); // 截至目前該方法涉及到安全問題已失效 // } </script> </body> </html>
使用execCommand命令存在以下缺陷:
(1)不夠靈活。只能操作input, textarea或具有contenteditable屬性的元素
(2)execCommand是同步操作,如果復(fù)制/粘貼大量數(shù)據(jù),頁(yè)面會(huì)出現(xiàn)卡頓。
(3)有些瀏覽器還會(huì)跳出提示框,要求用戶許可,這時(shí)在用戶做出選擇前,頁(yè)面會(huì)失去響應(yīng)。
(4)它只能將選中的內(nèi)容復(fù)制到剪貼板,無法向剪貼板任意寫入內(nèi)容
方式二:瀏覽器自帶clipboard API實(shí)現(xiàn)復(fù)制粘貼(推薦)
簡(jiǎn)介
ClipboardAPI是下一代的剪貼板操作方法,比傳統(tǒng)的document.execCommand()
方法更加強(qiáng)大、更合理。
特點(diǎn)
(1)它的所有操作都是異步進(jìn)行的,返回promise對(duì)象,不糊造成頁(yè)面卡頓,
(2)它可以將任何內(nèi)容(例如圖片)放入到剪貼板。
(3)安全。通過navigator.clipboard
屬性返回Clipboard對(duì)象,所有操作都通過這個(gè)對(duì)象進(jìn)行,如果navigator.clipboard
屬性返回undefined
,就說明當(dāng)前瀏覽器不支持這個(gè)API。
1)有時(shí)候用戶可能會(huì)把敏感數(shù)據(jù)(比如密碼)放在剪貼板允許腳本任意讀取會(huì)產(chǎn)生風(fēng)險(xiǎn),而通過Clipboard對(duì)象進(jìn)行判斷,則很好的避免了這個(gè)風(fēng)險(xiǎn)。
2)此外,有些瀏覽器規(guī)定(例如Chrome),只有HTTPS協(xié)議(或者開發(fā)環(huán)境、本地環(huán)境下)的頁(yè)面才能使用這個(gè)API,由于從 Chrome 76 開始,Clipboard API 將不再被允許在非加密環(huán)境下(即純 HTTP)使用。這是因?yàn)樵?HTTP 環(huán)境下,網(wǎng)絡(luò)傳輸是明文的,容易被竊聽和篡改,因此會(huì)引入安全風(fēng)險(xiǎn)。
3)其次,復(fù)制權(quán)限是用戶默認(rèn)賦予的,而粘貼權(quán)限是需要用戶手動(dòng)同意的,例如,在寫入剪貼板時(shí)腳本可以自動(dòng)完成,但是讀取剪貼板時(shí),瀏覽器會(huì)彈出一個(gè)對(duì)話框咨詢用戶是否同意讀取。
(4)有一點(diǎn)需要特別注意,腳本讀取的是當(dāng)前頁(yè)面的剪切板(注意我說的是瀏覽器中的剪貼板,而不是電腦操作系統(tǒng)自帶的剪貼板),這帶來一個(gè)問題,如果想把相關(guān)的代碼粘貼到開發(fā)者工具中直接運(yùn)行,可能會(huì)報(bào)錯(cuò),因?yàn)檫@時(shí)的當(dāng)前頁(yè)面是開發(fā)者工具的窗口,而不是網(wǎng)頁(yè)頁(yè)面。
例如:你把下面的代碼粘貼到開發(fā)者工具運(yùn)行就會(huì)報(bào)錯(cuò)。
(async () => { const text = await navigator.clipboard.readText(); console.log(text); })();
因?yàn)樵诖a運(yùn)行的時(shí)候,開發(fā)者工具窗口是當(dāng)前頁(yè),這個(gè)頁(yè)面不存在ClipboardAPI依賴的DOM接口。
解決辦法是將相關(guān)代碼放到setTimeout()里面延遲運(yùn)行,在調(diào)用函數(shù)之前快速點(diǎn)擊瀏覽器的頁(yè)面窗口,將其變成當(dāng)前頁(yè)。
setTimeout(async () => { const text = await navigator.clipboard.readText(); console.log(text); }, 2000);
clipboard對(duì)象及相關(guān)API
clipboard對(duì)象提供了四個(gè)方法用來讀寫剪貼板,他們都是異步方法,返回promise對(duì)象。
Clipboard.readText()
Clipboard.readText()
方法用來復(fù)制剪貼板(也就是粘貼功能)里面的文本數(shù)據(jù)。
該方法返回的是Promise對(duì)象,那么我這里提供兩種使用形式
- 形式一:pormise回調(diào)實(shí)現(xiàn)
// 普通方法 function paste() { navigator.clipboard // 創(chuàng)建clipboard對(duì)象 .readText() // 調(diào)用readText()方法 .then((clipText) => { // 成功回調(diào) console.log(clipText); // clipText是從剪貼板讀取到的內(nèi)容(也就是要粘貼的內(nèi)容) }) .catch((err) => console.log("粘貼失??!",err)); // 失敗回調(diào) }
- 形式二:async函數(shù)
// async 函數(shù) async function paste(){ try{ // 創(chuàng)建clipboard對(duì)象并調(diào)用readText()方法讀取剪貼板上的內(nèi)容進(jìn)行返回 const text = await navigator.clipboard.readText() console.log("要粘貼的內(nèi)容為:",text); // 具體粘貼到哪你自己決定 }catch(err){ // catch捕獲處理報(bào)錯(cuò) console.log("粘貼失敗!",err); } }
注意,如果用戶不允許使用這個(gè)API進(jìn)行粘貼操作,那么腳本就會(huì)報(bào)錯(cuò),那么我們就可以用catch()方法進(jìn)行處理報(bào)錯(cuò)。
Clipboard.read()
Clipboard.read()
方法用于復(fù)制剪貼板(也就是粘貼功能)里面的數(shù)據(jù),可以是文本數(shù)據(jù),也可以是二進(jìn)制數(shù)據(jù)(比如圖片)。該方法需要用戶明確給予許可。
該方法返回一個(gè) Promise 對(duì)象。一旦該對(duì)象的狀態(tài)變?yōu)?resolved,就可以獲得一個(gè)數(shù)組,每個(gè)數(shù)組成員都是 ClipboardItem 對(duì)象的實(shí)例。
下面我們簡(jiǎn)單介紹下代碼中用到的幾個(gè)對(duì)象屬性和方法
遍歷通過Clipboard.read()
方法成功回調(diào)得到的數(shù)組對(duì)象,由此得到一個(gè)個(gè)的ClipboardItem
對(duì)象,表示一個(gè)單獨(dú)的剪貼項(xiàng),每個(gè)剪貼項(xiàng)都擁有ClipboardItem.types屬性
和ClipboardItem.getType()方法
。
1、ClipboardItem.types屬性
返回一個(gè)數(shù)組,里面的成員是該剪貼項(xiàng)可用的 MIME 類型,比如某個(gè)剪貼項(xiàng)可以用 HTML 格式粘貼,也可以用純文本格式粘貼,那么它就有兩個(gè) MIME 類型(text/html和text/plain)。
2、ClipboardItem.getType(type)方法
用于讀取剪貼項(xiàng)的數(shù)據(jù),返回一個(gè) Promise 對(duì)象。該方法接受剪貼項(xiàng)的 MIME 類型作為參數(shù),返回該類型的數(shù)據(jù),該參數(shù)是必需的,否則會(huì)報(bào)錯(cuò)。
代碼示例如下:
- 形式一:promise回調(diào)實(shí)現(xiàn)
// 粘貼任何類型的數(shù)據(jù) function paste() { navigator.clipboard .read() // 調(diào)用read()方法從剪貼板讀取數(shù)據(jù)進(jìn)行粘貼操作 .then((clipboardItems) => { console.log(clipboardItems,"clipboardItems ========="); // clipboardItems是一個(gè)數(shù)組 for (const clipboardItem of clipboardItems) { console.log(clipboardItem, "clipboardItem ========="); // clipboardItem是一個(gè)實(shí)例對(duì)象 for (const type of clipboardItem.types) { // clipboardItem.types返回一個(gè)數(shù)組,存儲(chǔ)的是每一段剪貼板的mine數(shù)據(jù)類型 clipboardItem .getType(type) // 讀取接收到的mine類型作為參數(shù),返回該類型的數(shù)據(jù) .then((res) => console.log(res)) .catch((err) => console.log(err)); } } }) .catch((err) => { console.log(err.name,err.message) }); }
- 形式二:async函數(shù)+await實(shí)現(xiàn)
async function paste(){ try { const clipboardItems = await navigator.clipboard.read() for(const clipboardItem of clipboardItems){ for(const type of clipboardItem.types){ const result = await clipboardItem.getType(type) console.log(result); } } } catch (err) { console.log(err.name,err.message); } }
顯然使用第二種方式實(shí)現(xiàn)代碼更簡(jiǎn)單。
Clipboard.writeText()
Clipboard.writeText()
方法用于將文本內(nèi)容寫入剪貼板(也就是復(fù)制功能),該方法同樣返回一個(gè)Promise對(duì)象。
代碼示例如下:
下面代碼功能是:通過點(diǎn)擊頁(yè)面,將數(shù)據(jù)復(fù)制到剪貼板。
document.body.addEventListener('click',async (e) => { await navigator.clipboard.writeText('Yo') // 參數(shù)是要寫入的文本 } )
當(dāng)然你可以通過點(diǎn)擊一個(gè)按鈕,一個(gè)標(biāo)簽等來觸發(fā)該復(fù)制操作。
Clipboard.write()
Clipboard.write()
方法用于將任意數(shù)據(jù)寫入剪貼板,可以是文本數(shù)據(jù),也可以是二進(jìn)制數(shù)據(jù)。
該方法接受一個(gè) ClipboardItem 實(shí)例作為參數(shù),表示寫入剪貼板的數(shù)據(jù)。
- 代碼示例復(fù)制一個(gè)圖片類型
async function copy1() { try { // 圖片地址 const imgURL = "https://dummyimage.com/300.png"; // 獲取圖片 const data = await fetch(imgURL); // 將圖片轉(zhuǎn)為blob類型 const blob = await data.blob(); // 將數(shù)據(jù)寫入(復(fù)制)到剪貼板 await navigator.clipboard.write([ // 創(chuàng)建Clipboard實(shí)例對(duì)象,對(duì)象的鍵名是數(shù)據(jù)的 MIME 類型,鍵值就是數(shù)據(jù)本身 new ClipboardItem({ [blob.type]: blob, }), ]); console.log("Image copied."); } catch (err) { console.error(err.name, err.message); } }
ClipboardItem()
是瀏覽器原生提供的構(gòu)造函數(shù),用來生成ClipboardItem實(shí)例,它接收一個(gè)對(duì)象作為參數(shù),該對(duì)象的鍵名是數(shù)據(jù)的 MIME 類型,鍵值就是數(shù)據(jù)本身。
注意,Chrome 瀏覽器目前只支持寫入 PNG 格式的圖片。
此外,write()方法還可以將用一個(gè)剪貼項(xiàng)的多種格式的值寫入到剪貼板,一種是文本數(shù)據(jù),一種是二進(jìn)制數(shù)據(jù),供不同的場(chǎng)合粘貼使用。
function copy() { const image = await fetch('kitten.png'); // 獲取圖片類型的數(shù)據(jù) const blob = await image.blob(); // 將圖片轉(zhuǎn)為blob對(duì)象 const text = new Blob(['Cute sleeping kitten'], {type: 'text/plain'}); // 獲取文字類型的數(shù)據(jù)并轉(zhuǎn)為blob實(shí)例對(duì)象 const item = new ClipboardItem({ 'text/plain': text, [blob.type]: image }); await navigator.clipboard.write([item]); }
就是剪貼板中的剪貼項(xiàng)有兩種類型的數(shù)據(jù),在你要圖片時(shí),我就將剪貼板中的數(shù)據(jù)用圖片的形式給你粘貼使用,要用文字時(shí),就粘貼文字給你。
方式三:clipboard.js插件庫(kù)實(shí)現(xiàn)復(fù)制剪切(推薦)
它是一個(gè)不需要Flash,就能實(shí)現(xiàn)文本復(fù)制或者剪切到剪切板的輕量級(jí)插件(注意沒有粘貼哦)
官網(wǎng):clipboard.js
安裝引入
# node安裝 npm install clipboard --save
<!-- html文件中可以使用CDN引入 --> <script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js"></script>
// js文件中可以通過ES6語(yǔ)法的import或者commonjs進(jìn)行引入或者使用其他引入方式
這個(gè)庫(kù)同時(shí)依賴于Selection
和execCommand
api。所有瀏覽器都支持第一個(gè),而以下瀏覽器支持第二個(gè)。chrome42+,Edge12+,F(xiàn)irefox41+,IE9+,Opera2+,Safari0+
基本使用
總共有兩步,第一步在指定的html標(biāo)簽中使用指定屬性進(jìn)行綁定,第二部創(chuàng)建Clipboard實(shí)例對(duì)象調(diào)用相關(guān)的event事件,操作如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <!-- 引入clipboard.js --> <script src="https://cdn.bootcdn.net/ajax/libs/clipboard.js/2.0.11/clipboard.js"></script> <title>Document</title> </head> <body> <div> <!-- Target --> <input type="text" id="foo" value="要復(fù)制的內(nèi)容" /> <!-- Trigger --> <button class="btn" data-clipboard-target="#foo" data-clipboard-action="copy">復(fù)制</button> <!-- 有兩個(gè)屬性值: data-clipboard-target:取值是一個(gè)選擇器對(duì)象,用來綁定要復(fù)制的標(biāo)簽,復(fù)制其內(nèi)容 data-clipboard-action:用來決定是復(fù)制還是粘貼,有兩個(gè)取值:copy和cut --> </div> <script> // 創(chuàng)建一個(gè)實(shí)例對(duì)象,參數(shù)是一個(gè)選擇器,綁定的是觸發(fā)復(fù)制/剪切事件的標(biāo)簽 var clipboard = new ClipboardJS(".btn"); // 成功回調(diào) clipboard.on("success", function (e) { console.info("Action:", e.action); // 操作:copy或者cut console.info("Text:", e.text); // 復(fù)制/剪切的內(nèi)容 console.info("Trigger:", e.trigger); // 觸發(fā)對(duì)象 e.clearSelection(); }); // 失敗回調(diào) clipboard.on("error", function (e) { console.error("Action:", e.action); // 操作:copy或者cut console.error("Trigger:", e.trigger); // 觸發(fā)對(duì)象 }); </script> </body> </html>
可以通過ClipboardJS.isSupported()
方法判斷瀏覽器是否可以使用這個(gè)庫(kù)
進(jìn)階使用
new ClipboardJS("選擇器",{...})
方法,第二個(gè)參數(shù)是一個(gè)對(duì)象,你可以往里面?zhèn)魅牖卣{(diào)函數(shù),如下
(1)通過函數(shù)返回要綁定的節(jié)點(diǎn)target
new ClipboardJS('.btn', { target: function(trigger) { return trigger.nextElementSibling; } });
(2)通過函數(shù)設(shè)置要復(fù)制的文本內(nèi)容text
new ClipboardJS('.btn', { text: function(trigger) { return trigger.getAttribute('aria-label'); } });
(3)在Bootstrap Modals 中或與任何其他更改焦點(diǎn)的庫(kù)一起使用時(shí),將焦點(diǎn)元素設(shè)置為 container 值
new ClipboardJS('.btn', { container: document.getElementById('modal') });
(4)銷毀復(fù)制粘貼的實(shí)例對(duì)象(如果在單頁(yè)應(yīng)用中使用時(shí),要更精確地管理DOM的生命周期,可以使用以下方法清除創(chuàng)建的事件對(duì)象)
var clipboard = new ClipboardJS('.btn'); clipboard.destroy();
可以看到這個(gè)插件庫(kù)基本的功能是復(fù)制和剪切,沒有涉及到粘貼操作,所以,通常會(huì)和瀏覽器自帶clipboardAPI配合使用實(shí)現(xiàn)復(fù)制粘貼操作。
補(bǔ)充:復(fù)制粘貼操作攔截
主要用到了copy和paste事件
copy
例如:復(fù)制操作時(shí),將用戶放入到剪貼板中的文本轉(zhuǎn)為大寫
const source = document.querySelector('.source'); source.addEventListener('copy', (event) => { const selection = document.getSelection(); event.clipboardData.setData('text/plain', selection.toString().toUpperCase()); event.preventDefault(); });
上面示例中,事件對(duì)象的clipboardData屬性包含了剪貼板數(shù)據(jù)。它是一個(gè)對(duì)象,有以下屬性和方法。
Event.clipboardData.setData(type, data)
:修改剪貼板數(shù)據(jù),需要指定數(shù)據(jù)類型。Event.clipboardData.getData(type)
:獲取剪貼板數(shù)據(jù),需要指定數(shù)據(jù)類型Event.clipboardData.clearData([type])
:清除剪貼板數(shù)據(jù),可以指定數(shù)據(jù)類型。如果不指定類型,將清除所有類型的數(shù)據(jù)。Event.clipboardData.items
:一個(gè)類似數(shù)組的對(duì)象,包含了所有剪貼項(xiàng),不過通常只有一個(gè)剪貼項(xiàng)。
例如:攔截用戶的復(fù)制操作,將指定內(nèi)容放入剪貼板
onst clipboardItems = []; document.addEventListener('copy', async (e) => { e.preventDefault(); // 先使用該方法組織默認(rèn)事件,然后由腳本接管復(fù)制操作 try { let clipboardItems = []; for (const item of e.clipboardData.items) { if (!item.type.startsWith('image/')) { continue; } clipboardItems.push( new ClipboardItem({ [item.type]: item, }) ); await navigator.clipboard.write(clipboardItems); console.log('Image copied.'); } } catch (err) { console.error(err.name, err.message); } });
paste
用戶使用剪貼板數(shù)據(jù),進(jìn)行粘貼操作時(shí),會(huì)觸發(fā)paste事件
document.addEventListener('paste', async (e) => { e.preventDefault(); const text = await navigator.clipboard.readText(); console.log('Pasted text: ', text); });
總結(jié)
到此這篇關(guān)于JavaScript實(shí)現(xiàn)復(fù)制粘貼剪切功能的文章就介紹到這了,更多相關(guān)JS復(fù)制粘貼剪切功能內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript獲取網(wǎng)頁(yè)中第一個(gè)鏈接ID的方法
這篇文章主要介紹了JavaScript獲取網(wǎng)頁(yè)中第一個(gè)鏈接ID的方法,涉及javascript中document.links方法的使用,需要的朋友可以參考下2015-04-04js刪除對(duì)象中的某一個(gè)字段的方法實(shí)現(xiàn)
這篇文章主要介紹了js刪除對(duì)象中的某一個(gè)字段的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01使用JavaScript實(shí)現(xiàn)獲取頁(yè)面滾動(dòng)位置
這篇文章主要為大家詳細(xì)介紹了在JavaScript中如何獲取水平和垂直的滾動(dòng)位置,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2024-12-12js模擬jquery的slide和fadeIn和fadeOut功能
以前用過jquery的slideUp,slideDown,等許多很不錯(cuò)的方法,感覺很容易就能實(shí)現(xiàn)頁(yè)面元素的動(dòng)畫效果!2010-07-07固定背景實(shí)現(xiàn)的背景滾動(dòng)特效示例分享
固定背景滾動(dòng)特效,使用background-attachment: fixed和導(dǎo)航菜單,頁(yè)面會(huì)非常平滑的滾動(dòng),感興趣的朋友可以參考下哈希望對(duì)你有所幫助2013-05-05如何根據(jù)url?批量下載二維碼實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了如何根據(jù)url批量下載二維碼實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05深入理解JavaScript系列(26):設(shè)計(jì)模式之構(gòu)造函數(shù)模式詳解
這篇文章主要介紹了深入理解JavaScript系列(26):設(shè)計(jì)模式之構(gòu)造函數(shù)模式詳解,本文講解了基本用法、構(gòu)造函數(shù)與原型、只能用new嗎?、強(qiáng)制使用new、原始包裝函數(shù)等內(nèi)容,需要的朋友可以參考下2015-03-03JavaScript設(shè)計(jì)模式之建造者模式實(shí)例教程
這篇文章主要介紹了JavaScript設(shè)計(jì)模式之建造者模式,結(jié)合實(shí)例形式分析了設(shè)計(jì)模式中建造者模式的概念、功能及JavaScript實(shí)現(xiàn)與使用建造者模式的相關(guān)操作技巧,需要的朋友可以參考下2018-07-07