Navigator.clipboard与Canvas实现图片复制粘贴到微信上

1,214 阅读2分钟

前言:之前开发中使用过复制功能,那时候使用的是复制文本功能,然后有次业务需求需要用到右键事件来复制图片。

效果图:

image.png

有人说为什么不用原生右键保存图片,但是业务中右键事件不止复制图片,还有其他操作,自定义右键事件就需要阻止浏览器原生的事件。所以原生的右键点击保存图片方法不可取。

让我们先来理下思路,复制功能做过的大家都会先想到一个库clipboard.js,这是一个专门复制的库。我尝试过这个库来进行复制图片。可能是笔者姿势不对,没成功。所以笔者去查阅了原生的剪切板API——Navigator.clipboard # Clipboard

image.png

阅读文档可以得知通过Clipboard.write()来写入图片数据到剪切板。

语法:

var promise = navigator.clipboard.write(data)

参数:

data

ClipboardItem包含要写入剪贴板的数据的对象数组。(如果是处理文本数据那么直接使用Clipboard.readText()Clipboard.writeText()即可,但是如果是文件或者图片类型则需要用到这个对象。) ClipboardItem 可以让开发者更好得处理各种文件类型数据。

返回值:

Promise数据写入剪贴板后解析。如果剪贴板无法完成剪贴板访问,则该承诺将被拒绝。

通过文档说明,就有了大致思路:

代码首先创建一个新ClipboardItem对象,文本将被放置到该对象中以发送到剪贴板。传递给构造函数的对象的键ClipboardItem表示内容类型,值表示内容。内容可以是文本甚至是 Blob(例如,用于将图像复制到剪贴板)。Then同时指定一个实现函数和一个错误函数。

代码思路有了,那么再联系实际业务场景,在实际业务场景中,展示出来的图片以网络地址居多,而ClipboardItem对象需要传入的是Blob,所以我们需要先把网络图片转换为图片文件,这里笔者用到的是canvas.toBlob()

在创建canvas的时候需要给它设定宽高,这里需要注意,创建的画布宽高是图片的自然宽度和自然高度,也就是naturalWidthnaturalHeight,它们是元素的自然宽度,它们永远不会改变。而不是渲染在页面的高宽,如果使用图片在页面的宽高,会导致图片复制不全或者偏小。

思路都差不多了,剩下就是代码了。

<script>
//写在公共方法,暴露出去
/**
 * 复制图片至剪切板
 * @param htmlDom dom节点
 */
export function clipboardImg(html) {
  const testImg = html
  //可以使用document.querySelector(),document.getElementById()等来获取需要复制的img标签
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  const img = new Image();
  //创建一个画布,赋予画布宽高为图片的原始宽高
  canvas.width = testImg.naturalWidth;
  canvas.height = testImg.naturalHeight;
  //浏览器在加载图像时要使用匿名身份验证,以允许跨域资源共享(CORS)。
  img.crossOrigin = "Anonymous";
  img.src = testImg.src;
  img.onload = () => {
    //防止有缓存,绘制之前先清除画布
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.drawImage(img, 0, 0); 
    // 将canvas转为blob
    canvas.toBlob(async (blob) => {
      console.log(blob);
      const data = [
        new ClipboardItem({
          [blob.type]: blob,
        }),
      ]
      await navigator.clipboard.write(data).then(
        () => {
          Message({
            type: 'success',
            message: "复制成功"
          })
          console.log("Copied to clipboard successfully!");
        },
        () => {
          Message({
            type: 'error',
            message: "复制失败"
          })
          console.error("Unable to write to clipboard.");
        }
      );
    });
  };
}
</script>

运行效果:

image.png

image.png

注意:new ClipboardItem()这个实例对象因为安全性质原因需要在HTTPS环境下才能使用或者开发环境也可。但是在http环境下就不行。

这篇文章分享就到了这,如果觉得对你有所帮助,能否点个赞,激励下笔者创作,感谢您的阅读。