关于vue3中js实现复制图片文字到剪贴板的方案,以及图片-canvas-base64-blob之间的转换,以及复制echarts需求实现

管梓
2023-12-01

目录

点击按钮复制一个图片,或者文字到剪贴板,能在别处进行粘贴操作

预备知识:

js操作剪切版的方法

图片格式之间的转换

图片转base64

base64转blob 注意参数数据的范围

图片转blob 先经过canvas 转

应用: echarts 复制图片到剪贴板


点击按钮复制一个图片,或者文字到剪贴板,能在别处进行粘贴操作

场景:复制图片 复制echarts 等

预备知识:

js操作剪切版的方法

1. document.execCommand()方法

document.execCommand('copy')(复制)
document.execCommand('cut')(剪切)
document.execCommand('paste')(粘贴)

操作流程:

在网页中选中一段文字,之后我们可以通过点击复制按钮触发document.execCommand('copy')操作,之后就可以在你电脑中聚焦的位置 ctrl + v 实现复制

优点缺点:

只能将选中内容复制到剪贴板,并且复制粘贴过程是同步操作,大量复制时会阻塞

2. 异步Clipboard API

使用流程:

// 1. 获取Clipboard对象
const clipboardObj = navigator.clipboard;
// 2. 通过该对象方法进行写入   读取
clipboardObj.write(参数是clipboardItem实例)
clipboardObj.writeText(复制的文字)   写入之后就能ctrl V
clipboardObj.read()
clipboardObj.readText()

局限

read方法局限在同一页面窗口读取,并且兼容性较好,但不是最好,当网站是http的话不兼容

最核心方法详细介绍 -- clipboardObj.write

Clipboard.write()方法用于将任意数据写入剪贴板,一般是二进制数据,最常见的就是图片blob,该方法接收clipboardItem实例作为参数,表示写入剪贴板的数据

try {
  await clipboardObj.write(
    new ClipboardItem({
      []: blob   // key指的是blob的MIME类型   value指的是二进制字符串
      // 'image/png': blob     表示图片
      // text/html和text/plain   表示html文本  纯文本
    })
  )
} catch (err) {
  console.log()
}

3. 使用getSelection + execCommand api复制图片 好像好几个API已经被弃用

// 提前准备一个img标签   之后再看吧
有兴趣的  自己查查   反正不好用了

function getSelect(targetNode) {
  if (window.getSelection) {
    //chrome等主流浏览器
    var selection = window.getSelection();
    var range = document.createRange();
    range.selectNode(targetNode);
    selection.removeAllRanges();
    selection.addRange(range);
    console.log(selection, range);
  } else if (document.body.createTextRange) {
    //ie
    var range = document.body.createTextRange();
    range.moveToElementText(targetNode);
    range.select();
  }
  }
  const copyText = () => {
  
  const hidImg = document.getElementById("hidImg");
  
  const selection = window.getSelection(); // 清除选中
  
  getSelect(hidImg);
  document.execCommand("copy");
  //   window.getSelection().removeAllRanges();
  selection.removeAllRanges();
  };

  4. 拦截copy cut paste事件

用户向剪贴板放入数据,将触发copy事件 -- 拦截复制

用户向剪贴板放入数据,将触发cut事件 -- 拦截剪贴

用户向剪贴板放入数据,将触发paste事件 -- 拦截粘贴

事件对象:

拦截之后,先用e.preventDefault()取消了剪贴板的默认操作
事件对象的clipboardData属性包含了剪贴板数据。它是一个对象
Event.clipboardData.setData(type, data):修改剪贴板数据,需要指定数据类型。
Event.clipboardData.getData(type):获取剪贴板数据,需要指定数据类型。
Event.clipboardData.clearData([type]):清除剪贴板数据,可以指定数据类型。如果不指定类型,将清除所有类型的数据。
Event.clipboardData.items:一个类似数组的对象,包含了所有剪贴项,不过通常只有一个剪贴项。

图片格式之间的转换

图片转base64

  1. canvas将img转base64 --- 我的需求

局限: 注意如果是用的网上图片,会有跨域问题报错

<img id={"hidImg"} width={100} src={img} alt="" onLoad={load} />

// 获取图片   这里为了省事直接原生了,   为了更契合vue3建议使用ref获取dom

function getBase64Image(img) {
  let canvas = document.createElement("canvas");
  canvas.width = img.width;
  canvas.height = img.height;
  let ctx = canvas.getContext("2d");
  ctx?.drawImage(img, 0, 0, img.width, img.height);
  let dataURL = canvas.toDataURL("image/png");
  return dataURL;
  // return dataURL.replace("data:image/png;base64,", "");
}

const load = (e) => {
    let data = getBase64Image(e.target)
    // 得到了base64编码的图片的编码  有了这个就能复制了
}
  1. input 输入框 和FileReader实现 ---- 这个需要输入框操作 适用于预览和裁剪场景 之前写过 这次不写了

base64转blob 注意参数数据的范围

function convertBase64ToBlob(base64, type) {
      var bytes = window.atob(base64);
      var ab = new ArrayBuffer(bytes.length);
      var ia = new Uint8Array(ab);
      for (var i = 0; i < bytes.length; i++) {
          ia[i] = bytes.charCodeAt(i);
      }
      return new Blob([ab], { type: type });
}
// 参数是  base64数据  -- 注意是data:image/png;base64,之后的数据   type  是 MIME类型  
// 示例
const blobInput = convertBase64ToBlob(base64Data, 'image/png')

图片转blob 先经过canvas 转

<img id={"hidImg"} width={100} src={img} alt="" onLoad={load} />

function getBase64Image(img) {
  let canvas = document.createElement("canvas");
  canvas.width = img.width;
  canvas.height = img.height;
  let ctx = canvas.getContext("2d");
  ctx?.drawImage(img, 0, 0, img.width, img.height);
  canvas.toBlob(function(blob) {
    blobData.value  = blob   // blobData是定义的ref数据
  },'image/png')
}

const load = (e) => {
    getBase64Image(e.target)
}

思路:

文字思路就不说了,直接字符串传就行,图片:我们要把图片采用base64编码,再将base64编码转为blob字符串数据 ,之后采用类似文字复制的逻辑操作实现,有需求是复制echarts图表,复制到剪贴板

应用: echarts 复制图片到剪贴板

import { defineComponent, getCurrentInstance, onMounted, ref } from 'vue';

export default defineComponent({
  props: {
    option: {
      type: Object,
      default: () => ({})
    }
  },
  setup(props, { emit, slots }) {
    const chart_one = ref<HTMLElement | null>(null);
    const { appContext } = getCurrentInstance();
    const strImg = ref<string>('');

    const init = () => {
      console.log(chart_one.value, appContext.config.globalProperties.$echarts, 8888);
      let echarts = appContext.config.globalProperties.$echarts;
      let barChart = echarts.init(chart_one.value);
      // 数据是传来的  拿到数据初始化
      barChart.setOption(props.option);
      // echarts  API
      let picInfo = barChart.getDataURL();
      // 若得到的图片只有坐标轴   需要向options添加  animation : false,  
      if (picInfo) {
        strImg.value = picInfo.split(',')[1];
      }
      // 下信息ok了
    };

    const copy = function () {
      try {
        const base64Data = strImg.value;
        const blobInput = convertBase64ToBlob(base64Data, 'image/png');
        const clipboardItemInput = new ClipboardItem({ 'image/png': blobInput });
        navigator.clipboard.write([clipboardItemInput]).then(() => {
          console.log('success')// 做一个弹窗提示
        });
      } catch (e) {
        console.log(e);
      }
    };

    function convertBase64ToBlob(base64, type) {
      var bytes = window.atob(base64);
      var ab = new ArrayBuffer(bytes.length);
      var ia = new Uint8Array(ab);
      for (var i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
      }
      return new Blob([ab], { type: type });
    }

    onMounted(() => {
      init();
    });
    return () => (
      <div style={{ width: '100%' }}>
        <button onClick={copy}>复制图片</button>
        <div style={{ width: '100%', height: '500px' }} ref={chart_one} class="demo_one"></div>
      </div>
    );
  }
});

另一个解决方案 使用库clipboard-polyfill

clipboard-polyfill - npm

参考:

剪贴板操作 Clipboard API 教程 - 阮一峰的网络日志

查的还是挺多的,额 不是我不想展示,是真不知道该咋展示,  之后的话我有时间会补一些这方面工具,请各位看官方便食用

 类似资料: