JS實現將圖片複製到剪貼板

前言

最近項目新增需求:用戶可以拖拽頁面上的圖片文件到word文檔。
當操做瀏覽器裏拖拽圖片至別的程序,在word文檔中展現出獲取到的只是圖片的url地址,而非預期的圖片文件。在現有的拖拽事件所提供api沒法知足需求的狀況下,換一個思路走:嘗試將圖片複製到剪貼板html

對於原生js的複製操做,已有封裝好的庫clipboard.js,可是封裝得太死,沒法知足更多定製化的需求,主要表如今如下兩點:node

  1. 只接受click事件,沒法綁定其餘事件。
  2. 只複製目標節點的子節點,對於img標籤,若是不額外包裹一層父元素,沒法實現圖片複製。

參考clipboard.js源碼,瞭解了實現原理後(其實很是簡單!:) ),咱們就能本身動手封裝一個複製方法:git

概述

Range對象

Range表示包含節點和部分文本節點的文檔片斷。最多見的就是用戶在瀏覽器拖動鼠標選擇的內容(user selection)es6

clipboard.png

好比上圖這塊藍色高亮區域。github

在現代瀏覽器中(IE9以上),你能夠經過Document.createRange()方法或者new Range()建立一個Range對象;當須要獲取user selection時,你應該使用window.getSelection()方法獲取Selection對象web

有點懵?chrome

clipboard.png

剛瞭解了Range對象,而Selection對象又是什麼?閱讀了文檔以後,仍是疑惑它們之間的區別windows

clipboard.png
Selection對象表示用戶的選擇,而Range對象則表示文檔的連續部分,與任何視覺表示無關。一個Selection對象幾乎可由0到多個Range表示出來,固然,Range對象也能獨立於Selection而被徹底的建立和修改。api

簡單的演示代碼

html部分:數組

<p>
  這是一段文字
  AAAAAAAAAA
  BBBBBBBBBB
  <span id="range">Range</span>
</p>
<input id="input" type="text">
<button id="button1">選擇文字後點擊</button>
<button id="button2">點擊後將選中指定的節點</button>

js部分:

var btn1 = document.getElementById('button1'),
    btn2 = document.getElementById('button2'),
    input = document.getElementById('input'),
    rangespan = document.getElementById('range');
    
var selection = window.getSelection(),
    range = document.createRange();
btn1.addEventListener("click", function(event) {
    input.value = selection.toString();
}); 
btn2.addEventListener("click", function(event) {
    range.selectNode(rangespan);
    selection.removeAllRanges(); //刪除包含在selection本來的range,也就是取消用戶選中的範圍
    selection.addRange(range); //讓選中部分變成咱們本身定義的節點內容
});

演示地址

https://jsfiddle.net/muvhqcnf...

一點就會 :)

兼容陳舊IE版本

Microsoft提供了相似的TextRange接口。
在實際代碼部分會展現Microsoft TextRange的基本使用。

execCommand方法

execCommand方法容許運行命令來操縱可編輯區域的內容。該方法的第一個參數是命令的名稱,參數類型爲DOMString。
在這裏,咱們將利用execCommand方法的copy命令實現複製選中的內容:

document.execCommand('copy')

execCommand API起源於IE,後來被添加到HTML5(HTML Editing APIs),在各瀏覽器的表現會有不一樣。更多請查看文檔

咱們回到前面的演示代碼,將btn1的點擊事件替換成execCommand命令:

btn1.addEventListener("click", function(event) {
    //input.value = selection.toString();
    document.execCommand('copy');
});

拖動鼠標選擇文字,點擊按鈕後看看能粘貼出什麼:)

複製圖片功能的具體實現

封裝能夠兼容ie的getSelect方法

還記得前面的例子裏,咱們經過rangeselectNode(node)方法獲取節點, 再使用selectionremoveAllRanges()方法和addRange(range)將節點替換咱們獲取的節點。在這裏,咱們一樣能夠這樣選中咱們目標的img節點:

const getSelect = targetNode => {
  if (window.getSelection) {
    //chrome等主流瀏覽器
    var selection = window.getSelection();
    var range = document.createRange();
    range.selectNode(targetNode);
    selection.removeAllRanges();
    selection.addRange(range);
  } else if (document.body.createTextRange) {
    //ie
    var range = document.body.createTextRange();
    range.moveToElementText(targetNode);
    range.select();
  }
}

派發事件

爲了避免浪費性能,咱們使用事件委託到但願被複制的節點上。這裏對傳入的nodeName進行處理,方便自由的控制被複制一個或多個節點類型。默認爲<img>。

const clipboardHandler = (nodeName, event) => {
  event = event || nodeName; //不傳參時
  const type = Object.prototype.toString.call(nodeName).replace(/\[object\s|\]/g, '');
  const target = event.target || event.srcElement;

  var result = false;
  switch (type) {
    case 'String':
      result = (target.nodeName.toLowerCase() === nodeName);
      break;
    case 'Array':
      result = nodeName.some(item => target.nodeName.toLowerCase() === item);
      break;
    case 'Object':
      nodeName = null;
    default:
      result = (target.nodeName === 'IMG');
  }

  if (result) {
    //調用以前封裝好的getSelect方法
    getSelect(target);
    document.execCommand('copy');
  }
}

調用:

[element].addEventListener('mousedown', clipboardHandler); //預備拖動圖片按下鼠標時執行復制

傳遞參數(字符串或數組):

var [somename]Handler = clipboardHandler.bind(null, [nodeName]);
[element].addEventListener([eventType],[somename]Handler);

完整代碼演示地址

已驗證在chrome和ie8上可行(ie8須要對es6語法與bind和addEventListener方法進行pollyfill)

但願可以幫助到你:)

相關文章
相關標籤/搜索