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

news2025/3/14 11:44:22

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

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

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

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

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

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

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

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

1.1 document.execCommand()

使用方法:

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

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()方法将焦点设置到元素上。
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对象。

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()方法写入到剪贴板。

比如这样一张图片:

<img src="https://xxx" alt="加载失败" id="img"/>

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

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属性。

<img src="xxx" crossOrigin/>

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

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

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对象,具体代码如下:

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')来复制文本,或者直接给用户提示该浏览器不支持复制图片。

 // 将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,具体代码如下:

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

4.2 下载图片

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

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()进行低版本的兼容,另外还介绍了预览图片下载图片的实现思路,希望能帮助到大家!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2314843.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 8 设置允许远程连接(Windows环境)

&#x1f31f; MySQL 8 设置允许远程连接&#xff08;Windows环境&#xff09; 在开发和部署应用时&#xff0c;经常需要从远程主机连接到MySQL数据库。默认情况下&#xff0c;MySQL仅允许本地连接&#xff0c;因此需要进行一些配置才能允许远程访问。今天&#xff0c;我将详细…

我又又又又又又更新了~~纯手工编写C++画图,有注释~~~

再再再次感谢Ttcofee提的问题 本次更新内容&#xff1a; 鼠标图案&#xff08;切换&#xff09;&#xff0c;版本号获取&#xff0c;输入框复制剪切板 提前申明&#xff1a;如果运行不了&#xff0c;请到主页查看RedpandaDevc下载&#xff0c;若还是不行就卸了重装。 版本号&…

全面解析:将采购入库单数据集成到MySQL的技术实施

旺店通旗舰版-采购入库单集成到MySQL的技术案例分享 在数据驱动的业务环境中&#xff0c;如何高效、准确地实现系统间的数据对接是企业面临的重要挑战。本文将聚焦于一个具体的系统对接集成案例&#xff1a;将旺店通旗舰奇门平台上的采购入库单数据集成到MySQL数据库中&#x…

12. Pandas :使用pandas读Excel文件的常用方法

一 read_excel 函数 其他参数根据实际需要进行查找。 1.接受一个工作表 在 11 案例用到的 Excel 工作簿中&#xff0c;数据是从第一张工作表的 A1 单元格开始的。但在实际场景中&#xff0c; Excel 文件可能并没有这么规整。所以 panda 提供了一些参数来优化读取过程。 比如 s…

记录致远OA服务器硬盘升级过程

前言 日常使用中OA系统突然卡死&#xff0c;刷新访问进不去系统&#xff0c;ping服务器地址正常&#xff0c;立马登录服务器检查&#xff0c;一看磁盘爆了。 我大脑直接萎缩了&#xff0c;谁家OA系统配400G的空间啊&#xff0c;过我手的服务器没有50也是30台&#xff0c;还是…

Java网络多线程

网络相关概念: 关于访问: IP端口 因为一个主机上可能有多个服务, 一个服务监听一个端口,当你访问的时候主机通过端口号就能知道要和哪个端口发生通讯.因此一个主机上不能有两个及以上的服务监听同一个端口. 协议简单来说就是数据的组织形式 好像是两个人交流一样,要保证自己说…

VScode 运行LVGL

下载vscode解压 环境安装 安装mingw64&#xff0c;gcc 版本必须8.3以上 安装cmak 系统环境变量Path中添加&#xff08;以实际安装目录为准&#xff09; C:\Program Files\mingw64\bin C:\Program Files\CMake\bin 将GUI-Guider生成的代码目录拷贝一份放到vscode项目目录…

React Next项目中导入Echart世界航线图 并配置中文

公司业务要求做世界航线图&#xff0c;跑了三个ai未果&#xff0c;主要是引入world.json失败&#xff0c;echart包中并不携带该文件&#xff0c;源码的world.json文件页面404找不到。需要自己寻找。这是整个问题卡壳的关键点&#xff0c;特此贴出资源网址。 目录 一、安装 二…

QT与网页显示数据公式的方法

一.网页中显示数学公式通常有三种主要方法 1.图片方式 原理&#xff1a;将公式转换为图片&#xff08;如 PNG、SVG&#xff09;&#xff0c;通过 <img> 标签嵌入网页。 实现步骤&#xff1a; 使用工具&#xff08;如 LaTeX dvipng、在线生成工具&#xff09;将公式渲…

深入解析APP订阅页的运作机制(订阅页如何运作)

在当今数字经济的背景下&#xff0c;订阅模式已成为许多企业获取稳定收入的重要方式。无论是软件、视频流媒体还是电子商务&#xff0c;订阅服务都能为用户提供持续的价值体验。然而&#xff0c;如何有效地设计和运作一个订阅页&#xff0c;是决定用户是否愿意订阅的关键因素。…

Golang倒腾一款简配的具有请求排队功能的并发受限服务器

golang官方指南[1]给了一些代码片段&#xff0c;层层递进演示了信道的能力: 1>. 信号量2>. 限流能力 var sem make(chan int, MaxOutstanding) func Serve(queue chan *Request) {for req : range queue {req: reqsem <- 1 go func() { // 只会开启MaxOutstandin…

【运维】服务器系统从centos7重装为ubuntu22.04

目录 一、硬盘准备二、系统安装三、安装基本系统组件四、挂载机械硬盘五、问题解决 一、硬盘准备 【注意&#xff1a;这一步会把硬盘的数据清空&#xff0c;所以需要找一个空的U盘或者把U盘数据备份】 ubuntu22.04下载 需要先安装 bittorrent 下载完之后会打开一个网页 然后…

创新技术引领软件供应链安全,助力数字中国建设

编者按 随着数字化转型的加速&#xff0c;针对软件供应链的攻击事件呈快速增长态势&#xff0c;目前已成为网络空间安全的焦点。如何将安全嵌入到软件开发到运营的全流程&#xff0c;实现防护技术的自动化、一体化、智能化&#xff0c;成为技术领域追逐的热点。 悬镜安全作为…

【设计模式】建造者模式——工厂模式

三、建造者模式——工厂模式 3.1 工厂模式 创建一个类对象的传统方式是使用关键字new, 因为用new 创建的类对象是一个堆对象&#xff0c;可以实现多态。工厂模式通过把创建对象的代码包装起来&#xff0c;实现创建对象的代码与具体 的业务逻辑代码相隔离的目的(将对象的创建和…

蓝桥备赛(18)- 红黑树和 set 与 map(上)

对于二叉搜索树 &#xff0c; 平衡二叉树 &#xff0c; 以及红黑树 &#xff0c; 目前只需要了解背后的原理 &#xff0c; 不做代码实现的要求 &#xff0c; 重要的就是了解各种操作的时间复杂度即可 &#xff0c; 为set 与 map 做铺垫 一、二叉搜索树 1.1 基本概念 相较与于堆…

obeaver 连接oracle 库 模式乱码

下载orai18n-12.1.0.2.0.jar 库--添加文件--把提前下载好的jar 随便放在一个文件夹下--添加文件选中&#xff0c;然后点击找到类&#xff0c; 选择类&#xff0c;确定即可正常 下载地址&#xff1a;https://download.csdn.net/download/weixin_42845364/88368302

ChatGPT 使用教程:深度探索AI常用功能技巧

文章目录 前言一、ChatGPT介绍1.1 人工智能与自然语言处理的发展1.2 ChatGPT 的诞生与意义 二、ChatGPT 基础入门2.1 注册与登录2.2 对话界面介绍2.3 基本提问方式 三、常用功能详解3.1 文本生成3.2 问题回答3.3 语言翻译3.4 代码生成与调试 四、高级使用技巧4.1 指令优化4.2 多…

[HUBUCTF 2022 新生赛]messy_traffic

下载附件 看到文件类型直接用wireshark打开&#xff0c;对MySQL协议进行追踪流&#xff0c;并没有什么发现&#xff0c;后面对NO.437发现有用信息&#xff0c;http追踪流 发现**system(‘cat passwd.txt’);**这里是在打开查看passwd.txt&#xff0c;密码是"SignUpForHUBU…

铁人三项(第五赛区)_2018_rop题解

先启动靶机连接看看。 直接ls&#xff0c;就给我输出句话&#xff0c;看来不能直接拿flag。 那走下流程。 查下位数和其他信息&#xff1a; 可以看到是32位的包&#xff0c;开了NX&#xff0c;但没开其他保护。 用ida32打开looklook。 主函数就是个这&#xff0c;看到了弹出的…

Compose 实践与探索六 —— 动画的流程控制与 Transition

1、Block 参数&#xff1a;监听每一帧 animateTo() 与 animateDecay() 中都有一个函数类型的 block 参数&#xff1a; suspend fun animateDecay(initialVelocity: T,animationSpec: DecayAnimationSpec<T>,block: (Animatable<T, V>.() -> Unit)? null): An…