目录
点击按钮复制一个图片,或者文字到剪贴板,能在别处进行粘贴操作
场景:复制图片 复制echarts 等
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:一个类似数组的对象,包含了所有剪贴项,不过通常只有一个剪贴项。
局限: 注意如果是用的网上图片,会有跨域问题报错
<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编码的图片的编码 有了这个就能复制了
}
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')
<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图表,复制到剪贴板
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 API 教程 - 阮一峰的网络日志
查的还是挺多的,额 不是我不想展示,是真不知道该咋展示, 之后的话我有时间会补一些这方面工具,请各位看官方便食用