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)

但愿可以帮助到你:)

相关文章
相关标签/搜索