一、简介

浏览器允许 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 对象,不会造成页面卡顿。而且,它可以将任意内容(比如图片)放入剪贴板。

首先,我们可以使用 `document.execCommand()` 方法来实现异步的 Clipboard 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()`方法读取剪贴板中的文本内容。最后,我们在控制台输出一条消息显示粘贴的文本内容。

参考链接:无