JS实现将图片复制到剪贴板

2018-06-13 admin

前言

最近项目新增需求:用户能够拖拽页面上的图片文件到word文档。 当操作浏览器里拖拽图片至别的程序,在word文档中展示出获取到的只是图片的url地址,而非预期的图片文件。在现有的拖拽事件所提供api无法满足需求的情况下,换一个思路走:尝试将图片复制到剪贴板

对于原生js的复制操作,已有封装好的库clipboard.js,但是封装得太死,无法满足更多定制化的需求,主要表现在以下两点:

  1. 只接受click事件,无法绑定其他事件。
  2. 只复制目标节点的子节点,对于img标签,如果不额外包裹一层父元素,无法实现图片复制。

参考clipboard.js源码,了解了实现原理后(其实非常简单!:) ),我们就能自己动手封装一个复制方法:

概述

Range对象

Range表示包含节点和部分文本节点的文档片段。最常见的就是用户在浏览器拖动鼠标选择的内容(user selection)

clipboard.png

比如上图这块蓝色高亮区域。

在现代浏览器中(IE9以上),你可以通过Document.createRange()方法或者new Range()创建一个Range对象;当需要获取user selection时,你应该使用window.getSelection()方法获取**Selection对象**。

有点懵?

clipboard.png

刚了解了Range对象,而Selection对象又是什么?阅读了文档之后,还是疑惑它们之间的区别

clipboard.png Selection对象表示用户的选择,而Range对象则表示文档的连续部分,与任何视觉表示无关。一个Selection对象几乎可由0到多个Range表示出来,当然,Range对象也能独立于Selection而被完全的创建和修改。

简单的演示代码

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方法

还记得前面的例子里,我们通过range的_selectNode(node)_方法获取节点, 再使用selection的_removeAllRanges()_方法和_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('mouseenter', clipboardHandler); //预备拖动图片按下鼠标时执行复制

传递参数(字符串或数组):

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

完整代码演示地址

https://jsfiddle.net/wo945555… 已验证在chrome和ie8上可行(ie8需要对es6语法与bind和addEventListener方法进行pollyfill)

希望能够帮助到你:)

原文链接:https://segmentfault.com/a/1190000015278418

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-33993.html

文章标题:JS实现将图片复制到剪贴板

相关文章
Node.js 2014这一年发生了什么
Node.js 的 2014 年充满了不幸和争议. 这一年 Noder 们经历了太多的伤心事, 经历了漫长的等待, 经历了沉重的分裂之痛. 也许 Noder 们不想回忆14年 Node.js land 发生的事情, 但正因为痛才更有铭记的价...
2015-11-12
JavaScript实现PC手机端和嵌入式滑动拼图验证码三种效果
PC和手机端网站滑动拼图验证码效果源码,同时包涵了弹出式Demo,使用ajax形式提交二次验证码所需的验证结果值,嵌入式Demo,使用表单形式提交二次验证所需的验证结果值,移动端手动实现弹出式Demo三种效果 首先要确认前端使用页面,比如...
2017-03-17
React.js编程思想
JavaScript框架层出不穷,在很多程序员看来,React.js是创建大型、快速的Web应用的最好方式。这一款由Facebook出品的JS框架,无论是在Facebook还是在Instagram中,它的表现都非常出色。 使用React.j...
2015-11-12
从2014年的发展来展望JS的未来将会如何
&lt;font face=&quot;寰�杞�闆呴粦, Arial, sans-serif &quot;&gt;2014骞达紝杞�浠惰�屼笟鍙戝睍杩呴€燂紝鍚勭�嶈��瑷€灞傚嚭涓嶇┓锛屼互婊¤冻鐢ㄦ埛涓嶆柇鍙樺寲鐨勯渶姹傘€傝繖浜涜��...
2015-11-12
Vue.js组件tab实现选项卡切换
本文实例为大家分享了vue插件tab选项卡的具体代码,供大家参考,具体内容如下 效果图: 代码如下: &lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt; ...
2017-03-13
JavaScript教程:JS中的原型
Keith Peters 几年前发表的一篇博文,关于学习没有“new”的世界,其中解释了使用原型继承代替构造函数。两者都是纯粹的原型编码。 标准方法(The Standard Way) 一直以来,我们学习的在 JavaScript 里创建对...
2015-11-12
three.js实现围绕某物体旋转
话不多说,请看代码: 可以拖动右上角观察变化 &lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot; style=&quot;width: 100%; height:100%;&quot;&gt...
2017-02-17
NodeJS参考手册pdf版
下载地址:Nodejs参考手册PDF版下载 ...
2015-11-12
HTML5究竟会火到什么地步
这已经是第N次,HTML5火热了起来,这次的火热是否可以延续? H5的最大优势就是可以在网页上直接调试和修改,而且更重要的是,它几乎不用考虑用户的机型与适配性问题。智能手机主要被分裂为两大系统:Android和iOS,一个做应用的团队,怎么...
2015-11-12
Riot.js:不足1KB的MVP客户端框架
Riot.js是一款MVP(模型-视图-呈现)开源客户端框架,其最大的特点就是体积非常小,不足1KB,虽然体积小,但它可以帮助用户构建大规模的Web应用程序。 Riot.js是由Moot公司开发,目前最新版本为v0.9.2,遵循MIT开源许...
2016-03-11
回到顶部