目前,一共有三种方法可以实现剪贴板操作
Document.execCommand()方法- 异步的
Clipboard API copy事件和paste事件
Document.execCommand() 方法
Document.execCommand()是操作剪贴板的传统方法,支持复制、剪切和粘贴这三个操作。
document.execCommand('copy')(复制)document.execCommand('cut')(剪切)document.execCommand('paste')(粘贴)
import { ref, readonly } from 'vue';
export function useClipboard() {
const copiedText = ref('');
const isCopied = ref(false);
const copyToClipboard = (text) => {
const textArea = document.createElement('textarea');
textArea.value = text;
document.body.appendChild(textArea);
textArea.select();
if (document.execCommand('copy')) {
isCopied.value = true;
copiedText.value = text;
} else {
isCopied.value = false;
}
document.body.removeChild(textArea);
};
const clearCopiedText = () => {
isCopied.value = false;
copiedText.value = '';
};
return {
copiedText: readonly(copiedText),
isCopied: readonly(isCopied),
copyToClipboard,
clearCopiedText,
};
}
Document.execCommand() 是同步操作,如果复制/粘贴大量数据,页面会出现卡顿。有些浏览器还会跳出提示框,要求用户许可,这时在用户做出选择前,页面会失去响应。
Clipboard API
Clipboard API所有操作都是异步的,返回 Promise 对象,不会造成页面卡顿。- Chrome 浏览器规定,只有 HTTPS 协议的页面才能使用这个 API。不过,开发环境(
localhost)允许使用非加密协议。 - 调用时需要明确获得用户的许可。权限的具体实现使用了 Permissions API,跟剪贴板相关的有两个权限:
clipboard-write(写权限)和clipboard-read(读权限)。"写权限"自动授予脚本,而"读权限"必须用户明确同意给予。也就是说,写入剪贴板,脚本可以自动完成,但是读取剪贴板时,浏览器会弹出一个对话框,询问用户是否同意读取。 Clipboard.write()方法用于将任意数据写入剪贴板,可以是文本数据,也可以是二进制数据。
使用 canvas.toBlob 方法将画布内容转换为 Blob 对象,使用 navigator.clipboard.write(data) 尝试将数据写入剪贴板。
import { ref } from 'vue';
export function useImageClipboard() {
const copiedImage = ref(null);
const isCopied = ref(false);
const copyImageToClipboard = (imageSrc) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = imageSrc;
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
canvas.toBlob((blob) => {
const data = [new ClipboardItem({ 'image/png': blob })];
navigator.clipboard
.write(data)
.then(() => {
isCopied.value = true;
copiedImage.value = imageSrc;
})
.catch((error) => {
console.error('复制失败:', error);
isCopied.value = false;
});
}, 'image/png');
};
};
const clearCopiedImage = () => {
isCopied.value = false;
copiedImage.value = null;
};
return {
copiedImage,
isCopied,
copyImageToClipboard,
clearCopiedImage,
};
}
使用
<template>
<div>
<button @click="copyImage">复制图片</button>
<div v-if="isCopied">
<img :src="copiedImage" alt="已复制的图片" />
<button @click="clearCopiedImage">清除</button>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useImageClipboard } from "../hooks/useImageClipboard.js";
const { copiedImage, isCopied, copyImageToClipboard, clearCopiedImage } =
useImageClipboard();
const imageSrc = ref(
"https://cdn.pixabay.com/photo/2023/10/20/20/53/pears-8330221_1280.jpg"
);
const copyImage = () => {
copyImageToClipboard(imageSrc.value);
};
</script>
copy事件和paste事件
用户向剪贴板放入数据时,将触发copy事件。用户使用剪贴板数据,进行粘贴操作时,会触发paste事件。