当前位置: 首页 > article >正文

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

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

那么如何通过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.widthcanvas.height = img.heightconst 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 的 urlconst 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()进行低版本的兼容,另外还介绍了预览图片下载图片的实现思路,希望能帮助到大家!

相关文章:

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

最近开发中遇到一个需求&#xff0c;就是用户希望能通过直接点击按钮复制图片&#xff0c;然后就可以很方便的把图片发送到班群中&#xff0c;于是就有了复制图片的需求。 那么如何通过JavaScript来实现复制图片呢&#xff1f; 一、前置知识&#xff1a;如何实现复制&#xf…...

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;若还是不行就卸了重装。 版本号&…...

Python控制语句——循环语句-for

1.下面的语句哪个会无限循环下去()。 A、 for a in range(10): time.sleep(10) B、 while 1<10: time.sleep(10) C、 while True: break D、 a = [3,-1,2] for i in a: if i==-1: break 答案:B。1<10始终为True,循环体中又没有break的条件,故B会无限循环。 2.for s i…...

全面解析:将采购入库单数据集成到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端口 因为一个主机上可能有多个服务, 一个服务监听一个端口,当你访问的时候主机通过端口号就能知道要和哪个端口发生通讯.因此一个主机上不能有两个及以上的服务监听同一个端口. 协议简单来说就是数据的组织形式 好像是两个人交流一样,要保证自己说…...

【H2O2 | 软件开发】Axios发送Http请求

目录 前言 开篇语 准备工作 正文 概念 封装工具包 示例 结束语 前言 开篇语 本系列为短篇&#xff0c;每次讲述少量知识点&#xff0c;无需一次性灌输太多的新知识点。该主题文章主要是围绕前端、全栈开发相关面试常见问题撰写的&#xff0c;希望对诸位有所帮助。 如…...

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项目目录…...

AIP-165 按条件删除

编号165原文链接https://google.aip.dev/165状态批准创建日期2019-12-18更新日期2019-12-18 有时API需要提供一种机制&#xff0c;按照一些过滤参数删除大量资源&#xff0c;而非提供待删除的各资源名字。 这是一个稀有的场景&#xff0c;用于用户一次性删除数千或更多资源的…...

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;实现创建对象的代码与具体 的业务逻辑代码相隔离的目的(将对象的创建和…...

Java基础:枚举类enum入门案例

1.基础枚举定义与使用&#xff1a; package com.zxy;public class Main {public static void main(String[] args) { // 获取枚举值cars car cars.BMW;switch (car){case BMW :System.out.println("BMW");break;case BENZ :System.out.println("BENZ&…...

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

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

Spring Boot集成EasyExcel

1. 初始化Spring Boot项目 首先&#xff0c;使用Spring Initializr&#xff08;https://start.spring.io/&#xff09;生成一个基本的Spring Boot项目。选择以下依赖项&#xff1a; Spring WebLombok (用于减少样板代码)SLF4J (用于日志记录) 2. 添加依赖 在你的pom.xml文件…...

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 多…...

無人機的應用程序有那些可以部署在linux server 系統

Dronecode Project&#xff1a;由 Linux Foundation 主導的開源項目&#xff0c;提供無人機航空操作系統和導航工具的開發框架&#xff0c;適合開發者使用。 DeepSeek-R1&#xff1a;這是一個人工智能模型&#xff0c;適用於無人機的數據處理和分析&#xff0c;支持在 Linux 系…...

[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;看到了弹出的…...

package.json 依赖包约束及快速删除node_modules

文章目录 一、package.json版本约束1、初始项目安装2. 已有 yarn.lock 文件的项目安装3. 特殊情况手动修改 package.json 版本&#xff1a;使用 yarn upgrade 命令&#xff1a; 二、快速删除node_modules三、depcheck 检测npm未使用的依赖 一、package.json版本约束 1、初始项…...

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

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

虚拟机Contos7为啥不能被本机电脑访问?

1.查看防火墙是否开启 systemctl status firewalld.service 2.如果防火墙关闭就可以直接被访问 3.如果防火墙打开了我们需要开放端口(下面为防火墙一系列指令) # 关闭防火墙 systemctl stop firewalld.service# 打开防火墙 systemctl start firewalld.service# 关闭开启自启…...

【21】单片机编程核心技巧:if语句逻辑与真假判断

【21】单片机编程核心技巧&#xff1a;if语句逻辑与真假判断 七律 条件分野 if语句判真假&#xff0c;括号条件定乾坤。 非零为真零为假&#xff0c;大括号内藏玄门。 省略虽简风险在&#xff0c;代码规范护本根。 单片逻辑由心控&#xff0c;条件分支自成文。 注释&#xf…...