JavaScript如何实现复制图片功能?

最近开发中遇到一个需求,就是用户希望能通过直接点击按钮复制图片,然后就可以很方便的把图片发送到班群中,于是就有了复制图片的需求。

那么如何通过JavaScript来实现复制图片呢?

一、前置知识:如何实现复制?

既然要复制图片,那我们先看看前端是怎么实现复制功能的。

一般来说,实现复制有2种方案:

  1. document.execCommand()方法;
  2. Clipboard API

复制功能的安全限制:复制脚本需要放在监听事件回调里面进行执行,由用户触发(比如点击事件),如果直接执行脚本,浏览器可能会报错。

下面分别介绍下这2个方法:

1.1 document.execCommand()

使用方法:

先选中文本,然后调用 document.execCommand('copy'),即可将选中的文本复制到剪贴板。

js 复制代码
const input = document.getElementById("input");
input.select(); // 注意 input 框不能添加 disabled 属性,否则会影响 select() 方法
document.execCommand("copy");

同样的它还可以实现剪切粘贴功能。

  1. document.execCommand('cut'):剪切选中的文本到剪贴板。
  2. document.execCommand('paste'):从剪贴板粘贴文本到光标位置。

剪切功能的使用和复制一样,所以这里就不做演示了。我这边再演示一下粘贴功能。

粘贴功能有以下使用限制:

  1. 确保元素是可编辑的,比如inputtextareacontenteditable属性为true的元素。
  2. 确保元素是焦点元素,可以使用focus()方法将焦点设置到元素上。
js 复制代码
const target = document.getElementById('pasteTargetInput');
target.focus(); // 确保目标元素获得焦点
document.execCommand('paste'); // 尝试粘贴

但是现代浏览器比如(Chrome、Firefox、Edge)已经限制或废弃了 execCommand("paste") 的直接使用,所以不推荐用这个api了

最后总结一下,document.execCommand()是实现复制的一个传统方法,它的优缺点如下:

  1. 优点:低版本浏览器兼容性好,
  2. 缺点:
  • 已被web 标准弃用,不推荐使用。
  • 只能复制文本,不能复制图片或者二进制数据。
  • 只能讲选中的内容写入到剪贴板,不能直接写入自定义内容。
  • 它是同步操作,如果复制内容过多,会引起页面卡顿。

1.2 Clipboard API

在浏览器的BOM对象中,有一个APIclipboard,它提供了系统剪贴板的读写访问能力 ,可以实现剪切、复制和粘贴功能,我们可以通过window上的navigator对象直接访问到一个clipboard对象。

js 复制代码
console.log(navigator.clipboard);

clipboard提供了四个方法:

  1. read():从剪切板读取数据,它会返回一个Promise,并将数据包装成一个ClipboardItem对象回传,
  2. readText():从剪切板中读取文本,它会返回一个Promise对象,并将剪切板数据作为String回传,
  3. write():写入数据(ClipboardItem对象)到剪切板,它会返回一个PromisePromise成功意味着写入完成,
  4. writeText():写入文本到剪切板,它会返回一个PromisePromise成功意味着写入完成。

我们可以通过上面描述的write()writeText()方法实现复制功能,writeText()只能写入文本,而write()方法则可以写入任意数据,所以我们需要使用write()方法实现复制图片的功能。

二、实现复制图片

一般图片是通过两种形式加载:

  1. 远程URL,最常见的是cdn 地址,比如https://cdn.xxx.cn/example.png
  2. base64 URL,一些体积较小的图片通常会打包成base64字符串,以减少网站资源请求数量,比如data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...

不管是什么图片形式的图片,我们最终目的都是需要将它转化为blob对象,然后通过navigator.clipboard.write()方法写入到剪贴板。

比如这样一张图片:

html 复制代码
<img src="https://xxx" alt="加载失败" id="img"/>

我们可以通过 canvas 将图片复制到剪贴板,具体代码如下:

js 复制代码
function copyImage(img) {
  const canvas = document.createElement('canvas')
  canvas.width = img.width
  canvas.height = img.height
  const ctx = canvas.getContext('2d')
  ctx.drawImage(img, 0, 0, img.width, img.height)
  canvas.toBlob((blob) => {
    // 目前图片只支持 png 类型
    const clipboardItem = new ClipboardItem({ 'image/png': blob })
    navigator.clipboard.write([clipboardItem])
  })
}
img.addEventListener("click", () => {
  copyImage(img);
});

这里如果出现Uncaught SecurityError: Failed to execute 'toBlob' on 'HTMLCanvasElement'报错,可能是你使用的图片跨域了,首先确保图片资源服务器允许跨域使用,然后需要在img标签上增加crossOrigin属性。

html 复制代码
<img src="xxx" crossOrigin/>

当然实际业务中可能提供的只是一个图片点击后的跳转链接,需要先把链接转成一张二维码图片,再进行复制。

这里使用第三方库qrcode,把链接转化成二维码。

js 复制代码
import QRcode from 'qrcode';

async function copyImage(url) {
  // 转成 base64 的 url
   const url = await QRcode.toDataURL(link, {
      errorCorrectionLevel: 'H', // 纠错级别最高
      width: 128,
      margin: 2,
      scale: 1,
    });
    const blob = await (await fetch(url)).blob();
    const clipboardItem = new ClipboardItem({ 'image/png': blob })
    navigator.clipboard.write([clipboardItem])
}

我们这里通过QRcode.toDataURL()方法,拿到二维码的base64图片url,然后通过原生的fetch方法,把二维码图片转化成blob对象,最后以ClipboardItem形式写入到clipboard中。

除了fetch以外,还可以通过如下方式将base64图片转化为blob对象,具体代码如下:

js 复制代码
function dataURIToBlob(dataURI) {
    const base64Index = dataURI.indexOf(';base64,') + 8;
    const base64 = dataURI.substring(base64Index);
    const byteCharacters = atob(base64);
    const byteArrays = [];

    for (let i = 0; i < byteCharacters.length; i++) {
      byteArrays.push(byteCharacters.charCodeAt(i));
    }

    const byteArray = new Uint8Array(byteArrays);
    const blob = new Blob([byteArray], { type: 'image/png' });
    return blob;
}

三、clipboard兼容性问题

在一些浏览器上可能不支持Clipboard API,所以需要通过navigator.clipboard的值是否为undefined判断此浏览器是否支持复制功能,如果不支持Clipboard API的话,就无法复制图片了,这时候可以使用document.execCommand('copy')来复制文本,或者直接给用户提示该浏览器不支持复制图片。

js 复制代码
 // 将dataBase64复制到剪切板
function copyToClipboard(text) {
  let a = document.createElement('input');
  a.value = text;
  document.body.appendChild(a);
  a.select();
  document.execCommand('copy');
  a.remove();
}

function copyImage() {
  if (navigator.clipboard) {
     //...
      const clipboardItem = new ClipboardItem({ 'image/png': imgBlob });
      navigator.clipboard.write([clipboardItem]);
      console.log('复制成功');
  } else {
    copyToClipboard(img.src);
  }
}

四、其它功能

4.1 预览图片

预览图片主要依赖于URL.createObjectURL这个原生API,具体代码如下:

js 复制代码
function previewImage(img) {
  const url = URL.createObjectURL(blob);
  const img = document.createElement('img');
  img.src = url;
  document.body.appendChild(img);
}

4.2 下载图片

下载图片主要依赖于a标签的download属性,具体代码如下:

js 复制代码
function downloadImage(img) {
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = true;
  a.click();
  URL.revokeObjectURL(url);
  console.log('下载图片成功');
}

五、小结

本文主要介绍了前端如何实现复制图片的功能,核心是通过Clipboard API来实现的,如遇到浏览器兼容问题,可以考虑回退使用document.execCommand()进行低版本的兼容,另外还介绍了预览图片下载图片的实现思路,希望能帮助到大家!

相关推荐
@PHARAOH8 分钟前
HOW - 在 Mac 上的 Chrome 浏览器中调试 Windows 场景下的前端页面
前端·chrome·macos
月月大王2 小时前
easyexcel导出动态写入标题和数据
java·服务器·前端
JC_You_Know3 小时前
多语言网站的 UX 陷阱与国际化实践陷阱清单
前端·ux
Python智慧行囊3 小时前
前端三大件---CSS
前端·css
Jinuss3 小时前
源码分析之Leaflet中Marker
前端·leaflet
成都渲染101云渲染66664 小时前
blender云渲染指南2025版
前端·javascript·网络·blender·maya
聆听+自律4 小时前
css实现渐变色圆角边框,背景色自定义
前端·javascript·css
行走__Wz4 小时前
计算机学习路线与编程语言选择(信息差)
java·开发语言·javascript·学习·编程语言选择·计算机学习路线
-代号95274 小时前
【JavaScript】二十九、垃圾回收 + 闭包 + 变量提升
开发语言·javascript·ecmascript
牛马程序小猿猴5 小时前
17.thinkphp的分页功能
前端·数据库