发布于 2026-01-06 0 阅读
0

异步剪贴板 API:使用 JavaScript 访问剪贴板

异步剪贴板 API:使用 JavaScript 访问剪贴板

长期以来,访问用户剪贴板都不是一件令人愉快的事情。我们必须使用document.execCommandAPI 才能在用户剪贴板之间复制和粘贴文本,这涉及到以下步骤:

// #1. Use an input element
const input = document.querySelector('input');

// #2. Set the input's value to the text we want to copy to clipboard
input.value = 'hello there!';

// #3. Highlight the input's value
input.select();

// #4. Copy the highlighted text
document.execCommand('copy');
Enter fullscreen mode Exit fullscreen mode

input元素可以在过程中动态创建和移除,或者设置样式使其对用户不可见。我以前使用这种方法时,总觉得它看起来很糟糕,不够优雅。幸运的是,现在有了新的 Web API,让这一切变得简单多了!

异步剪贴板 API

异步剪贴板 API使 Web 应用程序能够轻松地以编程方式读取和写入系统剪贴板。关于此 API 的几点说明:

  • 可通过以下方式访问:navigator.clipboard
  • 该网站需要通过 HTTPS 或 localhost 提供服务。
  • 仅当页面是当前活动的浏览器标签页时才有效

现在让我们来看看与旧方法相比,它实际上有多么简单。

写入剪贴板

async function writeToClipboard(text) {
    try {
        await navigator.clipboard.writeText(text);
    } catch (error) {
        console.error(error);
    }
}
Enter fullscreen mode Exit fullscreen mode

该方法返回一个对象,我们可以通过链式调用或使用/Promise来等待其解析。只需这一行简短的代码,我们就将文本写入了剪贴板!.then()asyncawait

注意:在 Firefox 中,只有在响应用户手势调用时才会将文本写入剪贴板writeText(),否则会抛出异常。Chrome 无论用户是否执行手势都会将文本写入剪贴板。两者都允许在无需请求权限的情况下写入剪贴板。

从剪贴板读取数据

async function readFromClipboard() {
    try {
        const text = await navigator.clipboard.readText();
        console.log(text);
    } catch (error) {
        console.error(error);
    }
}
Enter fullscreen mode Exit fullscreen mode

此方法也返回一个值Promise,并且与写入剪贴板一样简单。网站首次尝试读取剪贴板内容时,浏览器会提示用户是否允许请求者进行此操作:

Chrome 浏览器中的剪贴板访问权限提示

注意:在 Chrome 浏览器中,当用户多次关闭剪贴板(据我观察约为 3 次)后,读取剪贴板的权限将自动被拒绝。

注意:截至撰写本文时,Firefox(版本 68)尚不支持此readText()方法,MDN 文档指出它仅在浏览器扩展中受支持。

检查剪贴板访问权限

我们可以使用权限 API检查我们是否拥有访问剪贴板的权限

await navigator.permissions.query({name: 'clipboard-read'});
// or 'clipboard-write' for permission to write

// sample result: {state: 'granted'}
Enter fullscreen mode Exit fullscreen mode

例如,我们可以利用这个结果来显示一些用户界面,让用户知道我们是否有权限访问剪贴板。

剪贴板事件

除了允许我们轻松地读写剪贴板之外,异步剪贴板 API 还提供了剪贴板事件。我们可以通过分别监听 `copy`、`cut` 和 `paste` 事件来获知用户何时执行了与剪贴板相关的操作,例如复制、剪切copycut粘贴paste

document.addEventListener('copy', event => {});
document.addEventListener('cut', event => {});
document.addEventListener('paste', event => {});
Enter fullscreen mode Exit fullscreen mode

writeText()使用异步剪贴板 API(例如通过 `getClipboard()` 或 `getClipboard () `)访问剪贴板时,这些事件不会触发;readText()但调用相应的命令时会触发document.execCommand。调用 ` event.preventDefault()cancel()` 会取消操作并保持剪贴板的当前状态。

这些事件仅在页面上执行操作时触发,而在其他页面或应用程序中执行操作时不会触发。

剪贴板event对象有一个DataTransferclipboardData对象属性。这允许我们覆盖将要写入剪贴板的数据,从而使我们能够以其他格式写入数据,例如text/html

document.addEventListener('copy', event => {
    event.preventDefault();
    event.clipboardData.setData('text/plain', 'COPY ME!!!');
    event.clipboardData.setData('text/html', '<p>COPY ME!!!</p>');
});
Enter fullscreen mode Exit fullscreen mode

这样做时,我们需要调用相应的函数event.preventDefault(),以便将自定义数据写入剪贴板,而不是原始数据。对于 `add`cut和 ` pasteadd` 事件,我们需要自行处理文档中内容的删除/插入操作。

图片支持

目前我们看到的异步剪贴板 API 版本仅支持文本读写,但看起来已经很棒了!该 API 最近新增了对图像的支持,使得通过编程方式读写图像到剪贴板变得非常容易!

注意:目前仅支持 PNG 图像,但将来会添加对其他图像格式(以及可能一般的文件格式)的支持。

将图像写入剪贴板

在将图像写入剪贴板之前,我们首先需要获取图像的Blob 对象。获取图像 Blob 对象的方法有多种:

  • 请用户通过文件输入框选择图像。
  • fetch()来自网络的图像以斑点形式呈现(带有response.blob()
  • 将图像绘制到 acanvas并调用canvas.toBlob()

一旦我们有了一个图像 blob(我们称之为imageBlob),我们需要创建一个ClipboardItem包含该图像 blob 的实例:

new ClipboardItem({ 'image/png': imageBlob})
Enter fullscreen mode Exit fullscreen mode

构造ClipboardItem函数接受一个对象,该对象的键是 MIME 类型,值是实际的 blob 数据。我们可以提供多个 MIME 类型和 blob 数据对,从而使用不同的类型来表示数据。

现在我们可以使用以下代码将图像写入剪贴板navigator.clipboard.write()

async function writeToClipboard(imageBlob) {
    try {
        await navigator.clipboard.write([
            new ClipboardItem({
                'image/png': imageBlob
            })
        ]);
    } catch (error) {
        console.error(error);
    }
}
Enter fullscreen mode Exit fullscreen mode

navigator.clipboard.write()它接受一个元素数组ClipboardItem,但截至撰写本文时,仅支持单个元素。这种情况将来很可能会改变。

从剪贴板读取图像

可以使用以下方法从剪贴板读取项目(不仅限于文本)navigator.clipboard.read()

async function readFromClipboard() {
    try {
        const items = await navigator.clipboard.read();
    } catch (error) {
        console.error(error);
    }
}
Enter fullscreen mode Exit fullscreen mode

它返回一个数组,ClipboardItem该数组反映了系统剪贴板的内容,尽管目前在 Chrome 中它只返回剪贴板中的最新项目。

我们可以遍历这个数组来获取每个元素。我们可以通过ClipboardItem它的items属性获取所有可用的 MIME 类型,并使用其异步方法获取特定类型的实际 blob 数据getType()

for (let item of items) {
    console.log(item.types); // e.g. ['image/png']

    for (let type of item.types) {
        const blob = await item.getType(type);
    }
}
Enter fullscreen mode Exit fullscreen mode

获取到数据块后,我们就可以对其进行任何操作了。我们可以使用FileReader API将数据块转换为我们需要的格式:

const reader = new FileReader();
reader.onload = () => {
    const data = reader.result;
    // e.g. 'data:image/png;base64,...'
};

reader.readAsDataURL(blob);
Enter fullscreen mode Exit fullscreen mode

异步剪贴板 APIwrite()及其read()方法提供了访问剪贴板的通用方法。实际上,前面讨论的 ` writeText()and`readText()方法只是它们的便捷方法,也可以使用write()`/`read()或使用类型为 `.` 的 blob 来完成text/plain

async function writeToClipboard(text) {
    try {
        await navigator.clipboard.write([
            new ClipboardItem({
                'text/plain': new Blob([text], {type: 'text/plain'})
            })
        ]);
    } catch (error) {
        console.error(error);
    }
}

async function readFromClipboard() {
    try {
        const items = await navigator.clipboard.read();
        for (let item of items) {
            const data = item.getType('text/plain');
            // convert `data` to string using FileReader API's
            // `.readAsText(data)` method
        }
    } catch (error) {
        console.error(error);
    }
}
Enter fullscreen mode Exit fullscreen mode

浏览器支持和功能检测

Chrome 66Firefox 63中已引入支持文本的异步剪贴板 API readText()Web 应用尚不支持)。截至撰写本文时,只有 Chrome 支持 PNG 图片,该功能在Chrome 76中推出。更多信息请参阅此浏览器兼容性表格。

navigator.clipboard我们可以通过检查是否存在,在支持功能检测的浏览器上利用此 API 。

if (navigator.clipboard) {
    // Safe to use Async Clipboard API!
} else {
    // Use document.execCommand() instead
}
Enter fullscreen mode Exit fullscreen mode

资源

感谢阅读本文,希望您喜欢并从中有所收获。以下是更多关于异步剪贴板 API 的学习资源:

文章来源:https://dev.to/arnellebalane/async-clipboard-api-accessing-the-clipboard-using-javascript-36pb