js複製到貼上板命令及第三方外掛 clipboard 、ZeroClipboard
最近做的一個專案中,有一個點選按鈕後,複製文字的需求,關於使用 JS
複製文字的情況,很久以前曾經看到過,不過也僅是稍稍有些印象,對於到底如何複製,是否有什麼相容性要求等,都一概不知,但覺得應該沒什麼難度的。
但是當我自己真正做起來的時候,才發現這其中存在不少坑,各種瀏覽器實現複製的方法都不一樣,而且無論怎麼做相容,似乎都不可能讓所有的瀏覽器都能實現複製到貼上板的功能。
幾種主要方法總結如下。
execCommand
關於複製到貼上板的功能,網上出現頻率最多的方法就是 execCommand
。
原理其實很簡單明確,首先獲取你想要複製的文字所在的元素,使用 js
選擇器即可,例如 document.getElementById('txt')
select
選擇到文字,最後呼叫 execCommand
方法進行復制。
function copy(){
let ele = document.getElementById('txt')
ele.select()
document.execCommand('Copy')
}
我用最新版 Chrome
試驗了一下,這裡的 select()
方法只對 input
或者 textarea
元素有效,只有txt
是 這兩個元素時,才有可能複製成功,其他元素全部失敗。
這裡需要說明的是,document.execCommand()
方法有很多引數,Copy
只是其中一個:
// 選中網頁中的全部內容
document.execCommand('selectAll')
// 開啟 命令,相當於單擊檔案中的開啟按鈕
document.execCommand('open)
// 另存為 命令,將當前頁面另存為
document.execCommand('saveAs)
// 列印 命令,需要存在印表機
document.execCommand('print)
// 剪貼選中的文字到剪貼簿
document.execCommand('Cut','false',null)
// 刪除選中的文字
document.execCommand(Delete','false',null)
... .等等
以上就是document.execCommand()
其中一部分使用方法,當然了,相容性堪憂,幾乎沒什麼瀏覽器實現,我用最新版的 Chrome
操作以上方法,沒一個有響應的。
除了配合 select
之外,input
元素還有一個 focus
方法,同樣可以達到此目的,例如,下面這段我直接從 MDN
抄來的程式碼。
<p>點選複製後在右邊textarea CTRL+V看一下</p>
<input type="text" id="inputText" value="測試文字"/>
<input type="button" id="btn" value="複製"/>
<textarea rows="4"></textarea>
<script type="text/javascript">
var btn = document.getElementById('btn');
btn.addEventListener('click', function(){
var inputText = document.getElementById('inputText');
var currentFocus = document.activeElement;
inputText.focus();
inputText.setSelectionRange(0, inputText.value.length);
document.execCommand('copy', true);
currentFocus.focus();
});
</script>
我在谷歌瀏覽器上實驗了一下,沒什麼卵用,因為人家已經註明了,除了 Firefox
之外,其他瀏覽器全都沒實現。
clipboardData
這個方法算是 IE
的私有方法,有的文章上說 firefox
也支援,可能之前比較古老的版本支援吧,我用最新版的火狐測試了一下,根本沒用,其他瀏覽器應該也都沒有(最起碼我的chrome
瀏覽器就不行。)
function copyToClipBoard(){
var clipBoardContent+=window.location.href;
window.clipboardData.setData("Text",clipBoardContent);
alert("複製成功");
}
上面程式碼我在 IE
上試了一下,確實可行,不過其他瀏覽器就沒反應了,因為根本沒有 clipboardData
這個方法。
IE
的 clipboardData
除了 setData
這個方法之外,還有 getData(sDataFormat)
從剪貼簿獲取指定格式(text, url
)的資料,以及清除剪貼簿中指定格式(text, url
)的資料 clearData(sDataFormat)
createTextRange
這個方法也只有在 IE
下能用,我用 chrome 360se firefox
分別測了一遍,全都報錯。
<input onclick="goCopy(this)" value="這是要複製的內容">
function goCopy(obj){
obj.select()
textRange=obj.createTextRange()
textRange.execCommand("Copy")
alert("複製成功!")
}
這種方法似乎和第一種方法一樣,但是還另外多了一行程式碼,就是這一句 js=obj.createTextRange()
,如果你要複製input
或者 textarea
元素中的所有內容,那麼多出來的這一句是多此一舉,但是如果你要只複製其中一部分文字,那麼 這個 createTextRange()
就能派上用場了,因為這個獲得了 obj.createTextRange()
的引用物件 textRange
,還有其他的一些方法和屬性,能夠使得複製操作的顆粒度更小。
屬性
屬性名 | 描述 |
---|---|
boundingHeight |
獲取繫結 TextRange 物件的矩形的高度 |
boundingLeft |
獲取繫結TextRange 物件的矩形左邊緣和包含TextRange 物件的左側之間的距離 |
offsetLeft |
獲取物件相對於版面或由offsetParent 屬性指定的父座標的計算左側位置 |
offsetTop |
獲取物件相對於版面或由offsetParent 屬性指定的父座標的計算頂端位置 |
htmlText |
獲取繫結TextRange 物件的矩形的寬度 |
text |
設定或獲取範圍內包含的文字 |
方法
方法名 | 描述 |
---|---|
moveStart(‘character’, 2) | 更改範圍的開始位置 |
moveEnd | 更改範圍的結束位置 |
collapse | 將插入點移動到當前範圍的開始或結尾 |
move | 摺疊給定文字範圍並將空範圍移動給定單元數 |
execCommand | 在當前文件、當前選中區或給定範圍上執行命令 |
select | 將當前選擇區置為當前物件 |
findText | 在文字中搜索文字並將範圍的開始和結束點設定為包圍搜尋字串。 |
以上屬性和方法在 IE
中皆有效,其他瀏覽器都不行。
第三方庫
關於複製貼上功能,基本上就是以上三種了,其他的也都是從這三種方法中細化出來的方法,只是一個複製到貼上板的功能就有那麼多注意事項,還有那麼多的相容性程式碼要寫,而且寫了之後還不一定所有瀏覽器都能用,簡直就是難為人嘛,不過按照我經驗來看,這種情況越複雜繁瑣,就越意味著妥妥的是要有第三方庫的節奏啊,搜了一下,果然是有。
ZeroClipboard.js
ZeroClipboard.js
是使用動態建立 flash
的方式,並利用 flash
將需要貼上的文字或者其他物件貼上到貼上板的,也就是說需要瀏覽器支援 flash
,flash
的支援度確實很高,幾乎所有瀏覽器都支援,但有的瀏覽器並不是預設支援 flash
,必須要使用者自己主動安裝才行,比如 chrome
,所有如果瀏覽器沒有 flash
,那麼此庫是用不了的。
除了一小部分不預設安裝 flash
的瀏覽器之外,此庫在桌面上的相容性很好,但是如今移動端基本上都是不支援 flash
的,所以想要在移動端用,還是悠著點好。
clipboard.js
clipboard.js
算是一個新銳了,在 github上迄今為止有 18500
多顆星,號稱是專為現代瀏覽器設計的複製貼上方案,不使用 flash
,不依賴其他庫,gzip
壓縮之後只有 3kb
的大小,相容性為 IE9+
。
此庫實現複製貼上功能使用的關鍵方法就是上面說到的 select()
和 execCommand
兩種結合,原理就是創建出一個隱藏的 input
或者 textarea
元素,結合兩種方法進行復制貼上。
這種方法在移動端也能用 ,但並不是所有的移動端瀏覽器都能用,據我測試情況來看,百度瀏覽器和chrome
移動端都是可以用的,但是 QQ瀏覽器
和 uc
瀏覽器都不支援,如果不是必須要相容所有瀏覽器,推薦使用此庫,因為你能用更現代的方式來組織程式碼,例如在 vue
等框架中使用此庫。
以下為在 vue
中使用 clipboard.js
新增點選複製到貼上板的功能示例。
<template>
<a href="javascript:;" @click="copyWx" :data-clipboard-text="wechat">複製微信</a>
</template>
<script>
// 引入 clipboard
import Clipboard from 'clipboard'
export default {
name: 'copyToClipboard',
props: ['wechat'],
methods: {
copyWx () {
let clipboard = new Clipboard('.wx')
clipboard.on('success', e => {
// 釋放記憶體
clipboard.destroy()
})
clipboard.on('error', e => {
// 不支援複製
alert('瀏覽器不支援自動複製,請手動複製微訊號')
// 釋放記憶體
clipboard.destroy()
})
}
}
</script>
clipboard.js
與ZeroClipboard.js
二者相比各有優勢,前者適合現代瀏覽器,使用方法也更加 modern
和 fashion
,更貼近目前前端領域的發展趨勢,這從它在github
上的 star
數量就可見一斑,後者則相容性更強,雖然 flash
目前已經宣佈正式退休
,但 想要讓 flash
徹底消失,還需要不短的時間,在這段時間內,ZeroClipboard.js
依然可以有所作為。