Clipboard API
Clipboard API的接口提供了一種讀寫操作系統剪貼板的方式,它有四個方法,分別是:
read
,從剪貼板讀取數據,比如圖片readText
,從剪貼板讀取文本write
,寫入數據(比如圖片)到操作系統剪貼板writeText
,寫入文本到剪貼板
我的需求是實現將文字寫入到剪貼板,使用writeText
方法即可:
const promise = navigator.clipboard.writeText(newClipText)
clipboard
是掛在navigator
對象下的,接受一個字符串作爲參數,返回一個Promise。如果寫入成功就會被resolve
,如果沒有權限則會被reject
很簡單,但是它的兼容性不怎麼樣:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Qod8RyMA-1575537196910)(http://image.oldzhou.cn/Fjk7CltiHWAv8h8aTged4jvu3s6q)]
可以看出,IE、Edge、Safari全軍覆沒,即便FireFox和Chrome也都是很新的版本才支持,所以在生產環境上這個API肯定是不能完全勝任的。
document.execCommand
這個方法可以用來操作可編輯區域(比如鼠標選擇的文本)的內容,實現富文本功能時大多會用到這個方法:
bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
返回值是一個Boolean,如果是false
代表操作不被支持。MDN上提示:注意不要用這個返回值去校驗瀏覽器的兼容性(不太明白原理,如此驗證會導致性能問題還是報錯?既然不用來驗證,返回值還有什麼用?)
它有三個參數:
(1)第一個參數是一個字符串,是要執行的命令的名稱。能夠執行的命令非常多,不僅僅包括我們後面會用到的將選中內容複製到剪貼板的copy
方法,還有例如fontSize
、insertImage
、cut
等方法,具體可以參考命令列表;
(2)第二個參數是一個Boolean,表示是否展示用戶界面,一般爲false
,因爲Mozilla沒有實現這個功能
(3)第三個參數是給一些命令使用的額外的參數,默認爲null
想要用它實現複製輸入框內容,必須有可編輯區域,比較常用的就是input
(或者是contenteditable
爲true
的區域),同時必須將可編輯區域中的內容,如果使用的容器是input
,那麼需要讓input
先focus
,然後通過input
的select
方法選中輸入框中的內容(如果是contenteditable
爲true
時則需要使用window.getSelection
獲得用戶選擇的文本範圍或光標位置)
在我們的需求中,可以利用現成的input
來當做容器,但是如果是作爲通用的方法,如果用戶雙擊一段文本後複製,那麼就需要自己動手創建一個input
來實現。但是這個input
應該是隱藏的,不應該被用戶發現,但是如果使用dispaly: none
是不行的,這樣是沒有辦法獲取到input
中的文本(用type="hidden"
也不行),所以我採用的是絕對定位,把input
定位到屏幕外,眼不見心不煩。
結合上面的Clipboard API,實現了一個公共方法(其中的Message
是一個用來提示的方法)
/**
* 將文字複製到系統剪切板
* @param { string } text 複製到剪切板的文字
*/
export function copyTextToClipboard(text) {
// 支持 Clipboard API 並且在安全環境下(localhost 或者 https)
if (navigator && navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
navigator.clipboard.writeText(text).then(() => {
Message({
message: '內容已複製到剪切板',
type: 'success',
duration: 1000,
});
}).catch(() => {
// 靜默失敗
});
} else if (document && document.execCommand && typeof document.execCommand === 'function') {
// 使用 execCommand 的後退方案
const input = document.createElement('input');
input.style.cssText = 'position: absolute; left: -9999px; top: -9999px; z-index: -9999;';
input.readOnly = true;
document.body.appendChild(input);
input.value = text;
input.focus();
input.select();
const isSucceed = document.execCommand('copy', true);
document.body.removeChild(input);
if (isSucceed) {
Message({
message: '內容已複製到剪切板',
type: 'success',
duration: 1000,
});
} else {
// 靜默失敗
}
}
}
document.execCommand
的兼容性還是相當不錯的:
所以上面的方法基本上可以滿足生產環境的要求了。
clipboard.js
實際上有現成的庫可以使用,那就是clipboard.js
,官網在這裏,Github的Star數和NPM的下載數都很高,並且壓縮後體積只有3KB,直接使用應該是沒有什麼問題的。
它可以從一個元素複製、剪切文本,也可以從性中來複制文本,比如在Vue中我們可以直接使用在一個Button元素上,通過v-bind
綁定一個響應式數據在data-clipboard-text
屬性上,就可以實現點擊Button進行復制的功能
<button class="btn" :data-clipboard-text="copyValue">Copy</button>
它還有對應的成功或者失敗的回調函數:
var clipboard = new ClipboardJS('.btn');
clipboard.on('success', function(e) {
console.info('Action:', e.action);
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);
e.clearSelection();
});
clipboard.on('error', function(e) {
console.error('Action:', e.action);
console.error('Trigger:', e.trigger);
});
更多的細節和高級用法可以參考它的官網。
它主要使用就是Selection
和execeCommand
這兩個API,所以兼容性也是很不錯的:
它的源碼也不是很複雜,可以閱讀這篇文章對源碼的解讀,其實自己去讀一下也是可以的。
總結
所以,如果需要實現的功能不太複雜,那麼上面自己封裝的函數應該可以滿足需求,如果需要頻繁使用或者需要一些高級功能,那麼可以直接使用clipboard.js
。