H5 的複製操做

一開始,在 Web 端,並無任何能夠接觸到 clipborad 的內容。之前,咱們想要執行 copy/paste/cut 只能藉助 flash。但如今,偉大的 H5 又或者說 W3C 推出了關於 H5 操控 clipboard 的草案。最出名的就是兩個 API:react

  • document.execCommand()git

  • ClipboardEventgithub

咱們一步一步來了解一下。先來看一下經典 execCommand 的使用。web

複製操做

input 複製

咱們須要先了解一下,基本的複製過程:瀏覽器

  • 選中(select)app

  • 複製(command + c || ctrl + c)dom

實際效果就是:spa

copy_select

而,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 就這麼一些:

直接看 demo 吧

這裏,我貼一下關鍵代碼:

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 複製

首先, 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): 設置相關的數據信息,主要用於 copycut 的相關事件中。

      • 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 相關

前面看起來也挺簡單的。固然,有同窗會想,不是還有其餘事件好比 cut, paste 嗎?是否是也能夠這麼作呢?
額...
一開始,我也是這麼想的,但現實每每會給您一個輕輕的愛撫。由於,爲了防止你惡意的獲取用戶信息,在 Chrome 中,通常而言你是不能經過 document.execCommand('paste') 觸發 paste 事件。不過,在手機端中,規矩是,你能夠在可編輯的元素中觸發 cutpaste , 只能在有效的 選中 元素中,觸發 copy。

根據上面的說法,咱們能夠經過利用 paste 的相關方法,來具體應用到實踐中。好比,防止用戶粘貼信息。這特別適用於那些作題頁面,防止你查資料而後 copy 相關答案。

document.addEventListener('paste',function copy (e) {
            e.preventDefault();
        });

固然,還有更狠的,直接禁止 copypastecut 事件。

['cut', 'copy', 'paste'].forEach((event)=>{
    document.addEventListener(event, (e)=>{
        e.preventDefault();
    });
});

方案總結

HTML5 如今能完美提供給咱們的應該就是 copy 事件的使用,對於市面上的 clipboard.js 差很少也是運用上述的知識點。根據上面的描述,能夠了解到,想要實現複製功能有三種漸進退化方案。如下兼容性由高到低:

如今 React 比較火,這裏我簡單的寫了一個 copybtn 組件。具體的使用 README 已經寫清楚了,若是有什麼不懂的地方能夠 @我。

相關文章
相關標籤/搜索