一、简介
浏览器允许 JavaScript 脚本读写剪贴板,自动复制或粘贴内容。然而,为了遵循用户的预期,脚本通常不应该改动用户的剪贴板。尽管如此,有时候实现“一键复制”等功能确实能带来便利。目前,共有三种方法可以实现剪贴板操作,本文将逐一介绍这三种方法。
二、Document.execCommand() 方法
Document.execCommand() 支持复制、剪切和粘贴这三个操作。以下是使用该方法的示例:
```javascript
document.execCommand('copy');
document.execCommand('cut');
document.execCommand('paste');
```
(1)复制操作
要执行复制操作,可以使用以下代码:
```javascript
const inputElement = document.querySelector('#input');
inputElement.select();
document.execCommand('copy');
```
注意,复制操作最好放在事件监听函数里面,由用户触发(例如用户点击按钮)。如果脚本自主执行,某些浏览器可能会报错。
(2)粘贴操作
要执行粘贴操作,可以使用以下代码:
```javascript
const pasteText = document.querySelector('#output');
pasteText.focus();
document.execCommand('paste');
```
(3)缺点
然而,Document.execCommand() 方法存在一些缺点:
首先,它只能将选中的内容复制到剪贴板,无法向剪贴板任意写入内容。其次,它是同步操作,如果复制/粘贴大量数据,页面会出现卡顿。有些浏览器还会跳出提示框,要求用户许可,这时在用户做出选择前,页面会失去响应。
为了解决这些问题,浏览器厂商提出了异步的 Clipboard API。这种 API 的所有操作都是异步的,返回 Promise 对象,不会造成页面卡顿。而且,它可以将任意内容(比如图片)放入剪贴板。
```javascript
document.execCommand('copy');
```
接下来,我们可以使用 `navigator.clipboard` API。由于用户可能把敏感数据(比如密码)放在剪贴板,允许脚本任意读取会产生安全风险,所以这个 API 的安全限制比较多。
```javascript
const clipboardObj = navigator.clipboard;
```
需要注意的是,脚本读取的总是当前页面的剪贴板。这带来的一个问题是,如果把相关的代码粘贴到开发者工具中直接运行,可能会报错,因为这时的当前页面是开发者工具的窗口,而不是网页页面。为了解决这个问题,我们可以使用 `setTimeout()` 函数来延迟执行代码。
```javascript
setTimeout(async () => {
const text = await navigator.clipboard.readText();
console.log(text);
}, 2000);
```
上面代码粘贴到开发者工具运行后,快速点击一下网页的页面窗口,使其变为当前页,这样就不会报错了。
最后,我们可以使用 `Clipboard` 对象来读写剪贴板。它提供了四个方法,用来读写剪贴板。它们都是异步方法,返回 Promise 对象。
```javascript
Clipboard.readText().then((text) => {
console.log(text);
});
```
在上述示例中,当用户点击页面后,将输出剪贴板中的文本。请注意,此时浏览器会弹出一个对话框,询问用户是否同意脚本读取剪贴板。
4.1 使用 try...catch
```javascript
async function getClipboardContents() {
try {
const text = await navigator.clipboard.readText();
console.log('Pasted content:', text);
} catch (err) {
console.error('Failed to read clipboard contents:', err);
}
}
```
4.2 使用 Clipboard.read()
```javascript
async function getClipboardContents() {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
console.log(URL.createObjectURL(blob));
}
}
} catch (err) {
console.error(err.name, err.message);
}
}
```
4.3 ClipboardItem.getType()
```javascript
ClipboardItem.types: ['text/html', 'text/plain']
ClipboardItem.getType(type): Promise
```
以下是重构后的代码:
```javascript
document.body.addEventListener('click', async () => {
await navigator.clipboard.writeText('Yo');
});
async function copyPageUrl() {
try {
await navigator.clipboard.writeText(location.href);
console.log('Page URL copied to clipboard');
} catch (err) {
console.error('Failed to copy: ', err);
}
}
async function copyImage() {
try {
const imgURL = 'https://dummyimage.com/300.png';
const data = await fetch(imgURL);
const blob = await data.blob();
await navigator.clipboard.write([
new ClipboardItem({ [blob.type]: blob }),
]);
console.log('Image copied.');
} catch (err) {
console.error(err.name, err.message);
}
}
```
1. 将点击事件监听器添加到 `document.body`,当用户点击时,向剪贴板写入文本数据 "Yo"。
2. `copyPageUrl` 函数用于将网页的 URL 复制到剪贴板。如果成功,输出 "Page URL copied to clipboard";如果失败,输出错误信息。
3. `copyImage` 函数用于将一张图片复制到剪贴板。首先从指定的 URL 获取图片数据,然后将其转换为二进制格式,并创建一个 `ClipboardItem` 实例,最后将该实例写入剪贴板。如果成功,输出 "Image copied.";如果失败,输出错误信息。
```javascriptfunction copy() {
const image = await fetch('kitten.png');
const text = new Blob(['Cute sleeping kitten'], {type: 'text/plain'});
const item = new ClipboardItem({
'text/plain': text,
'image/png': image
});
await navigator.clipboard.write([item]);
}
// 将用户放入剪贴板的文本转为大写
const source = document.querySelector('.source');
source.addEventListener('copy', (event) => {
const selection = document.getSelection();
event.clipboardData.setData('text/plain', selection.toString().toUpperCase());
event.preventDefault();
});
// Event.clipboardData.setData(type, data)
// Event.clipboardData.getData(type)
// Event.clipboardData.clearData([type])
// Event.clipboardData.items
```
在上述示例中,我们演示了如何拦截复制和粘贴操作。
首先,我们定义了一个名为`clipboardItems`的空数组。然后,我们使用`addEventListener`方法监听`copy`事件。当用户执行复制操作时,该事件将被触发。在这个事件处理器中,我们首先调用`preventDefault()`方法来阻止浏览器默认的复制行为。接下来,我们遍历`e.clipboardData.items`,并检查每个项目的类型是否以`image/`开头。如果是图片项目,则将其添加到`clipboardItems`数组中。最后,我们使用`navigator.clipboard.write()`方法将所有选中的项目写入剪贴板,并在控制台输出一条消息表示图片已复制。
对于粘贴操作,我们同样使用`addEventListener`方法监听`paste`事件。当用户执行粘贴操作时,该事件将被触发。在这个事件处理器中,我们首先调用`preventDefault()`方法来阻止浏览器默认的粘贴行为。接下来,我们使用`navigator.clipboard.readText()`方法读取剪贴板中的文本内容。最后,我们在控制台输出一条消息显示粘贴的文本内容。
参考链接:无