一開始,在 Web 端,並無任何能夠接觸到 clipborad 的內容。之前,咱們想要執行 copy/paste/cut 只能藉助 flash。但如今,偉大的 H5 又或者說 W3C 推出了關於 H5 操控 clipboard 的草案。最出名的就是兩個 API:react
document.execCommand()git
ClipboardEventgithub
咱們一步一步來了解一下。先來看一下經典 execCommand
的使用。web
咱們須要先了解一下,基本的複製過程:瀏覽器
選中(select)app
複製(command + c || ctrl + c)dom
實際效果就是:spa
而,execCommand 也是遵循這一過程來實現這樣的效果。若是咱們想使用 execCommand 執行 copy
的話,那麼應該先選中你想複製的元素。
這裏,另外還會使用到一個新的 API, window.getSelection()
。具體來講就是:.net
getSelection(): 用來得到當前選中的元素的內容。通常而言就是用鼠標選中頁面上的內容。code
toString(): 用來將選中的內容直接變爲 text 文本。
基本使用就是:
// 輸出選中的文本 window.getSelection().toString();
咱們通常只是使用該 API 進行輔助做用。最多見的作法就是動態建立 input 元素,而後動態制定 input[value]。執行 select(), 進行選中,而後執行 copy 便可。
# 總的代碼就是 function copyContent(elementId) { // 動態建立 input 元素 var aux = document.createElement("input"); // 得到須要複製的內容 aux.setAttribute("value", document.getElementById(elementId).innerHTML); // 添加到 DOM 元素中 document.body.appendChild(aux); // 執行選中 // 注意: 只有 input 和 textarea 能夠執行 select() 方法. aux.select(); // 得到選中的內容 var content = window.getSelection().toString(); // 執行復制命令 document.execCommand("copy"); // 將 input 元素移除 document.body.removeChild(aux); }
固然,若是你想不動態添加 input 元素,想直接 copy 的指定 DOM 元素的話,應該怎麼作呢?這裏就須要使用到 HTML5 新提供的 createRange()
相關方法。固然,上面的 getSelection()
也是其中之一。用到的 API 有:
document.createRange(): 用來建立選中容器。返回一個 range Object。 該 API 的兼容性,也是挺好的,手機端和 PC 端都支持。
selectNode(DOM): 返回 range Object 上掛載的方法。用來添加選中元素。只能添加一個
window.getSelection()
addRange(range): 這個方法是掛載到 getSelection() 方法下的,用來執行元素的選中。(!很重要)
上面 API 就這麼一些:
這裏,我貼一下關鍵代碼:
var copyDOM = document.querySelector('#selector'); var range = document.createRange(); // 選中須要複製的節點 range.selectNode(copyDOM); // 執行選中元素 window.getSelection().addRange(range); // 執行 copy 操做 var successful = document.execCommand('copy'); try { var msg = successful ? 'successful' : 'unsuccessful'; console.log('copy is' + msg); } catch(err) { console.log('Oops, unable to copy'); } // 移除選中的元素 window.getSelection().removeAllRanges();
這裏須要額外提醒一下,不能自動執行上述 copy 操做。即,在沒有任何用戶交互操做下,是不能執行 copy 等交互行爲的。因此,這裏須要用到 click 事件來輔助(固然,你也可使用其餘事件來進行代替)。
首先, clipboard 是最近提出來的,因此它的兼容性仍是須要等待時間去驗證的,目前的兼容性是支持一些簡單的 event。
若是,你的瀏覽器支持 ClipboardEvent
Constructor 的話。那麼 複製操做就變得異常簡單。
// 固然,下面的代碼應該放在某個交互的 click 事件中。 var copyEvent = new ClipboardEvent('copy', { dataType: 'text/plain', data: 'My string' }); document.dispatchEvent(copyEvent);
若是沒有的話,就只能使用在 document 的 copy 事件中返回的 event.clipboardData API 來設置或者獲取相關的信息。咱們得到 clipboardData 對象只能經過事件回調來實現:
e.clipboardData: 只能經過 document 上的copy/paste/cut 事件來獲取
document.addEventListener('copy', function(e){ // 設置信息,實現複製 e.clipboardData.setData('text/plain', 'Hello, world!'); e.preventDefault(); });
clipboardData: 該 obj 還掛載兩個經常使用的 API
setData(format, data): 設置相關的數據信息,主要用於 copy
和 cut
的相關事件中。
format: 就是基本的 MIME type。最經常使用的就是 text/plain
。具體內容能夠參考 MIME references
data: 就是對應 MIME type 放入的具體數據內容
getData(format): 通常用於 paste
事件中。用來獲取 clipboard 裏面的內容。不過,須要制定正確的解碼格式(就是設置好正確的 MIME type)。而且,該方法只能在 paste 事件中使用。
上面感受就是簡單的介紹一下 API,接下來正式說一些乾貨。若是使用 clipboardData 實現自定義複製內容。這樣,你不單單能夠複製頁面上簡單的 text 文本,還能夠複製圖片信息等。
看代碼
// 在指定 DOM 上綁定交互事件 DOM.addEventListener('click',function(){},false){ // 添加 copy 內容 document.addEventListener('copy',function copy (e) { msg = `<${msg}/>`; e.clipboardData.setData('text/plain', msg); e.preventDefault(); }) // 執行 copy 命令 document.execCommand('copy'); // 移除綁定事件 document.removeEventListener('copy','copy'); }
前面看起來也挺簡單的。固然,有同窗會想,不是還有其餘事件好比 cut
, paste
嗎?是否是也能夠這麼作呢?
額...
一開始,我也是這麼想的,但現實每每會給您一個輕輕的愛撫。由於,爲了防止你惡意的獲取用戶信息,在 Chrome 中,通常而言你是不能經過 document.execCommand('paste')
觸發 paste 事件。不過,在手機端中,規矩是,你能夠在可編輯的元素中觸發 cut
和 paste
, 只能在有效的 選中 元素中,觸發 copy。
根據上面的說法,咱們能夠經過利用 paste 的相關方法,來具體應用到實踐中。好比,防止用戶粘貼信息。這特別適用於那些作題頁面,防止你查資料而後 copy 相關答案。
document.addEventListener('paste',function copy (e) { e.preventDefault(); });
固然,還有更狠的,直接禁止 copy
,paste
,cut
事件。
['cut', 'copy', 'paste'].forEach((event)=>{ document.addEventListener(event, (e)=>{ e.preventDefault(); }); });
HTML5 如今能完美提供給咱們的應該就是 copy 事件的使用,對於市面上的 clipboard.js 差很少也是運用上述的知識點。根據上面的描述,能夠了解到,想要實現複製功能有三種漸進退化方案。如下兼容性由高到低:
input 模式
clipboard 直接操做
如今 React 比較火,這裏我簡單的寫了一個 copybtn 組件。具體的使用 README 已經寫清楚了,若是有什麼不懂的地方能夠 @我。