JavaScript 實現複製文字功能

前言

實際開發上,我們會需要按下某個按鈕就複製某一段文字,最常見就是複製優惠卷或者訂單編號等,所以這一篇紀錄一下有幾種方式可以達到將文字複製到剪貼簿的功能。

execCommand

早期最常使用的就是 document.execCommand('copy'); 語法,但是這邊要注意一件事情,在 MDN 文件中已經有說明 document.execCommand 是一個過時的語法

已废弃: This feature is obsolete. Although it may still work in some browsers, its use is discouraged since it could be removed at any time. Try to avoid using it.

翻譯:這個功能已經過時了。儘管它在某些瀏覽器中仍然可以工作,但它的使用是不鼓勵的,因為它可能在任何時候被刪除。盡量避免使用它。

execCommand + input

一種常見的做法就是使用選取匡的方式,因此就會需要 input 欄位來達成,而撰寫方式也很簡單

1
2
3
<input type="text" id="text">

<button type="button" id="btn">複製</button>
1
2
3
4
5
6
const select = (DOM) => document.querySelector(DOM);

select('#btn').addEventListener('click', () => {
select('#text').select();
document.execCommand("copy");
})

我們可以看到主要是透過 select() 語法選取 input 欄位中的文字在執行複製的行為,當然如果這也適用於 textarea

(這邊要注意 select 語法在 iOS 上無法正常運作,因此要使用 setSelectionRange。)

1
2
3
4
5
<input type="text" id="text">
<button type="button" id="btn">複製</button>
<br>
<textarea id="textarea" cols="30" rows="10"></textarea>
<button type="button" id="textarea-btn">複製</button>
1
2
3
4
5
6
7
8
9
10
11
const select = (DOM) => document.querySelector(DOM);

select('#btn').addEventListener('click', () => {
select('#text').select();
document.execCommand("copy");
})

select('#textarea-btn').addEventListener('click', () => {
select('#textarea').select();
document.execCommand("copy");
})

See the Pen copy text(1) by Ray (@hsiangfeng) on CodePen.

execCommand + Range

如果不想要透過 input 欄位來做的話,則是使用選取範圍的寫法,也就是 createRange 語法來達到,因此一開始必須先建立一個 Range 物件

1
const range = document.createRange();

將你要選取的元素放到 Range 物件中

1
2
const texts = select('#text');
range.selectNode(texts);

接下來這邊會有點特別,需要在使用到 window.getSelection 語法,該語法主要用途是代表著使用者的選取範圍,因此要建立 Selection 物件

1
const selection = window.getSelection();

當建立好 Selection 物件後,就要將剛剛我們剛剛定義的範圍,給加入到 Selection 中,類似告知他我們要選取這個範圍

1
selection.addRange(range);

最後補上 document.execCommand("copy"); 就完成了。

1
2
3
4
5
6
7
8
9
10
11
12
const select = (DOM) => document.querySelector(DOM);

select('#btn').addEventListener('click', (e) => {
// 建立 Range 物件
const range = document.createRange();
const texts = select('#text');
range.selectNode(texts);
// 取得 Selection 物件
const selection = window.getSelection();
selection.addRange(range);
document.execCommand("copy");
})

當然有些人會為了確保每一次選取,所以可以補上 selection.removeAllRanges 以確保選取的是新的,且也不會出現反白選取的狀況

See the Pen copy text(1) by Ray (@hsiangfeng) on CodePen.

那為了解決 document.execCommand 淘汰的問題,因此我們就要改使用較新的語法,也就是 Clipboard API,在 MDN 文件中我們可以看到他有說明 Clipboard API 提供了剪下、複製與貼上的功能,因此就可以拿來取代 document.execCommand 語法。

以剛剛的範例來講,只需要調整成以下即可

1
2
<input type="text" id="text">
<button type="button" id="btn">複製</button>
1
2
3
select('#btn').addEventListener('click', () => {
navigator.clipboard.writeText(select('#text').value);
})

但是這邊要特別注意到 Clipboard API 是非同步的,而他本身也是一個 Promise 語法,因使若你要跳出警告視窗告知複製成功的話,可以這樣寫

1
2
3
4
5
6
select('#btn').addEventListener('click', () => {
navigator.clipboard.writeText(select('#text').value)
.then(() => {
console.log('複製成功');
});
})

當然也可以使用 async/await

1
2
3
4
5
6
7
8
select('#btn').addEventListener('click', async() => {
try {
await navigator.clipboard.writeText(select('#text').value);
console.log('複製成功');
} catch(error) {
console.error(error);
}
})

See the Pen copy text(1) by Ray (@hsiangfeng) on CodePen.

相較 document.execCommand 來講 Clipboard API 是比較方便容易的,但是也因為比較新的關係,因此要注意瀏覽器的相容性問題。

參考文獻

Liker 讚賞

這篇文章如果對你有幫助,你可以花 30 秒登入 LikeCoin 並點擊下方拍手按鈕(最多五下)免費支持與牡蠣鼓勵我。
或者你也可以考慮請我喝一杯咖啡

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ