剪贴板 API 和事件

W3C 工作草案,

关于本文档的更多详情
此版本:
https://www.w3.org/TR/2025/WD-clipboard-apis-20250516/
最新发布版本:
https://www.w3.org/TR/clipboard-apis/
编辑草案:
https://w3c.github.io/clipboard-apis/
先前版本:
历史:
https://www.w3.org/standards/history/clipboard-apis/
反馈:
GitHub
规范内联
编辑:
(Google)
(Microsoft)
前任编辑:
(Mozilla)
(Microsoft)
说明文档:
异步剪贴板 API 说明文档

摘要

本文档描述了用于访问系统剪贴板数据的 API。它提供了覆盖默认剪贴板操作(剪切、复制和粘贴)以及直接访问剪贴板内容的操作。

本文档状态

本节描述了本文档在发布时的状态。当前的 W3C 出版物列表以及本技术报告的最新修订版可以在 W3C 标准和草案索引(网址为 https://www.w3.org/TR/)中找到。

本文档由 Web 编辑工作组作为工作草案发布,采用推荐标准流程。 作为工作草案发布并不意味着 W3C 及其成员的认可。

这是一份草案文件,随时可能被其他文件更新、替换或废弃。 将本文档作为正在进行的工作以外的内容引用是不合适的。

本文档的更改可以在 https://github.com/w3c/clipboard-apis 上跟踪。

本文档由在 W3C 专利政策下运作的小组制作。W3C 维护一份与该小组的可交付成果相关的任何专利披露的公开列表;该页面还包括披露专利的说明。任何实际知晓某项专利,并认为该专利包含基本权利要求的个人,必须按照W3C 专利政策第 6 节的规定披露该信息。

本文档受 2023 年 11 月 3 日 W3C 流程文档的约束。

1. 引言

本节是非规范性的。

本规范定义了系统剪贴板如何向 Web 应用程序公开。

本规范描述了两种通用 API:

2. 用例

本节是非规范性的。

2.1. 更改默认剪贴板操作

在许多情况下,需要更改默认的剪贴板操作(剪切/复制/粘贴)。以下是一些示例:

2.2. 远程剪贴板同步

对于与远程设备通信的 Web 应用程序(例如,远程访问或远程 shell 应用程序),通常需要在两个设备之间保持剪贴板数据同步。

此用例的一个重要方面是,它需要在没有用户手势或交互的情况下访问剪贴板。

要将剪贴板数据从远程设备复制到本地剪贴板,Web 应用程序将获取远程剪贴板数据,然后将数据 write() 到本地剪贴板。
要将本地剪贴板数据复制到远程设备,Web 应用程序将侦听 clipboardchange 事件,每当剪贴板更新时从剪贴板 read() ,然后将新的剪贴板数据发送到远程设备。

2.3. 触发剪贴板操作

为用户代理提供备用界面的应用程序有时需要能够触发用户代理中的剪贴板操作。

例如,考虑一个屏幕阅读器应用程序,它为标准 Web 浏览器提供更易于访问的界面。虽然阅读器可以显示内容并允许用户与之交互,但像剪贴板复制这样的操作需要在底层浏览器中进行,以确保正确设置剪贴板内容(以及浏览器在复制过程中添加的任何元数据)。

3. 术语

术语 可编辑上下文 指任何作为 编辑宿主、textarea 元素或其 type 属性设置为 "text"、"search"、"tel"、"url"、"email"、"password" 或 "number" 之一的 input 元素的元素。

4. 模型

平台提供一个 系统剪贴板

系统剪贴板有一个系统剪贴板项目列表,这些项目统称为 系统剪贴板数据

每个系统剪贴板项目都有一个系统剪贴板表示列表。

每个系统剪贴板表示都有一个名称(一个字符串)和数据(一个字节序列)。

5. 剪贴板事件

5.1. 剪贴板事件接口

ClipboardEvent 接口扩展了 Event 接口。

dictionary ClipboardEventInit : EventInit {
    DataTransfer? clipboardData = null;
};
clipboardData

一个 DataTransfer 对象,用于保存与事件相关的数据和元数据。

[Exposed=Window]
interface ClipboardEvent : Event {
    constructor(DOMString type, optional ClipboardEventInit eventInitDict = {});
    readonly attribute DataTransfer? clipboardData;
};
clipboardData

clipboardData 属性是 DataTransfer 接口的一个实例,它允许脚本在用户发起的复制、剪切和粘贴操作期间读取和操作系统剪贴板上的值。关联的拖放数据存储是系统剪贴板的实时但经过筛选的视图,公开了实现知道脚本可以安全访问的强制数据类型。对于合成事件,拖放数据存储包含创建事件的脚本添加的数据。

clipboardData 对象的 itemsfiles 属性支持处理来自剪贴板的多部分或非文本数据。

该接口可用于构造事件。 下面给出一个示例:

var pasteEvent = new ClipboardEvent('paste');
pasteEvent.clipboardData.items.add('My string', 'text/plain');
document.dispatchEvent(pasteEvent);

注意: 合成的剪贴板事件实际上不会修改剪贴板或文档。换句话说,虽然上面的脚本会触发粘贴事件,但数据不会被粘贴到文档中。

5.2. 剪贴板事件

5.2.1. clipboardchange 事件

系统剪贴板的内容发生更改时,会触发 clipboardchange 事件。这些更改可能由以下任何原因(非详尽列表)引起:

如果剪贴板内容在用户代理外部发生更改,则当用户代理重新获得焦点时,必须触发 clipboardchange 事件。

由于合成的 cutcopy 事件不会更新系统剪贴板, 因此它们不会触发 "clipboardchange" 事件。

5.2.2. copy 事件

当用户发起复制操作时,用户代理会触发一个名为 copy 的剪贴板事件。

如果事件未被取消,则当前选定的数据将被复制到系统剪贴板。 当前文档选择不受影响。

copy 事件会冒泡,可以取消,并且是组合事件。

有关此事件处理模型的详细说明,请参阅 § 8.1 复制操作

可以手动构造和分派合成的 copy 事件,但它不会影响系统剪贴板的内容。

5.2.3. cut 事件

当用户发起剪切操作时,用户代理会触发一个名为 cut 的剪贴板事件。

可编辑上下文中,如果事件未被取消,则该操作会将当前选定的数据放置在系统剪贴板上,并从文档中删除所选内容。 在删除所选数据之前会触发 cut 事件。剪切操作完成后,选择将折叠。

在非可编辑上下文中,clipboardData 将是一个空列表。请注意,在这种情况下仍会触发 cut 事件。

cut 事件会冒泡,可以取消,并且是组合事件。

有关此事件处理模型的详细说明,请参阅 § 8.2 剪切操作

可以手动构造和分派合成的 cut 事件,但它不会影响文档内容或系统剪贴板的内容。

5.2.4. paste 事件

当用户发起粘贴操作时,用户代理会触发一个名为 paste 的剪贴板事件。 在将任何剪贴板数据插入文档之前会触发该事件。

如果光标位于可编辑上下文中,则粘贴操作将以给定上下文支持的最合适格式(如果有)插入剪贴板数据。

粘贴操作在非可编辑上下文中无效,但无论如何都会触发 paste 事件。

paste 事件会冒泡,可以取消,并且是组合事件。

有关此事件处理模型的详细说明,请参阅 § 8.3 粘贴操作

可以手动构造和分派合成的 paste 事件,但它不会影响文档内容。

5.3. 与其他脚本和事件的集成

5.3.1. 允许修改剪贴板的事件处理程序

如果满足以下任一条件,事件处理程序可以写入剪贴板:

如果实现作者认为其他受信任的事件类型可能表达用户意图,则实现可以允许这些事件类型修改剪贴板。实现还可以支持信任特定站点或应用程序修改剪贴板的配置,而不管脚本线程的来源如何。

合成的 cutcopy 事件不得修改系统剪贴板上的数据。

5.3.2. 允许从剪贴板读取的事件处理程序

如果满足以下任一条件,事件处理程序可以从系统剪贴板读取数据:

合成的 paste 事件不得授予脚本访问真实系统剪贴板上数据的权限。

5.3.3. 与富文本编辑 API 的集成

如果实现支持通过脚本执行剪贴板命令的方法,例如通过使用命令 "cut"、"copy" 和 "paste" 调用 document.execCommand() 方法,则实现必须触发相应的操作,这将再次分派关联的剪贴板事件。

以下是通过脚本 API 触发复制、剪切或粘贴操作时要遵循的步骤:

  1. 同步执行相应的操作。

  2. 使用操作的返回值作为 API 调用的返回值。

注意: 通过脚本 API 触发的复制和剪切命令仅在事件是由受信任且由用户触发的事件分派,或者实现配置为允许此操作时,才会影响真实剪贴板的内容。通过脚本 API 触发的粘贴命令仅在实现配置为允许此操作时才会触发粘贴事件并授予对剪贴板内容的访问权限。如何配置实现以允许对剪贴板的读取或写入访问超出了本规范的范围。

5.3.4. 与其他事件的交互

如果剪贴板操作是由键盘输入触发的,则实现必须触发启动剪贴板操作的相应事件。该事件是异步的,但必须在相关键的 keyup 事件之前分派。

剪切和粘贴操作可能导致实现分派其他支持的事件,例如 textInput、input、change、验证事件、DOMCharacterDataModified 和 DOMNodeRemoved / DOMNodeInserted。任何此类事件都将排队,以便在剪切/粘贴事件处理完成后触发。

实现不得响应复制操作而分派其他与输入相关的事件,例如 textInput、input、change 和验证事件。

5.3.5. 修改选择或焦点的事件侦听器

如果事件侦听器修改选择或可聚焦区域,则剪贴板操作必须在修改后的选择上完成。

6. 剪贴板事件 API

剪贴板事件 API 允许您覆盖用户代理的默认剪切、复制和粘贴行为。

对剪贴板的访问是使用标准的 DataTransfer 方法来改变 ClipboardEventclipboardData 属性上的 items 来执行的。 这样做的结果之一是,这些剪贴板 API 只能在 ClipboardEvent 处理程序的上下文中访问剪贴板数据。

注意: 如果您需要在剪贴板事件处理程序之外访问剪贴板,请参阅 § 7 异步剪贴板 API

注意: 剪贴板事件 API 是同步的,因此它们的功能有限。这些 API 不支持可能阻塞的操作(例如请求权限或转码图像)。有关可以支持阻塞或其他耗时操作的更强大 API,请参阅 § 7 异步剪贴板 API

6.1. 覆盖复制事件

要覆盖默认的 copy 事件行为,必须添加一个 copy 事件处理程序,并且此事件处理程序必须调用 preventDefault() 来取消事件。

为了使用 clipboardData 中的数据更新系统剪贴板,需要取消事件。 如果未取消 ClipboardEvent,则将复制当前文档选择中的数据。

// 覆盖复制到剪贴板的内容。
document.addEventListener('copy', function(e) {
    // e.clipboardData 最初为空,但我们可以将其设置为
    // 我们希望复制到剪贴板的数据。
    e.clipboardData.setData('text/plain', 'Hello, world!');
    e.clipboardData.setData('text/html', '<b>Hello, world!</b>');

    // 这是防止将当前文档选择写入剪贴板所必需的。
    e.preventDefault();
});

6.2. 覆盖剪切事件

要覆盖默认的 cut 事件行为,必须添加一个 cut 事件处理程序,并且此事件处理程序必须调用 preventDefault() 来取消事件。

为了使用 clipboardData 中的数据更新系统剪贴板,需要取消事件。 如果未取消 ClipboardEvent,则将复制当前文档选择中的数据。

请注意,取消 cut 事件还将阻止更新文档(即,不会删除当前选择)。事件处理程序将需要手动更新文档以删除当前选定的文本。

// 覆盖复制到剪贴板的内容。
document.addEventListener('cut', function(e) {
    // e.clipboardData 最初为空,但我们可以将其设置为
    // 我们希望作为剪切操作的一部分复制到剪贴板的数据。
    // 写入我们希望复制到剪贴板的数据。
    e.clipboardData.setData('text/plain', 'Hello, world!');
    e.clipboardData.setData('text/html', '<b>Hello, world!</b>');

    // 由于我们将取消剪切操作,因此需要手动
    // 更新文档以删除当前选定的文本。
    deleteCurrentDocumentSelection();

    // 这是防止将文档选择写入剪贴板所必需的。
    e.preventDefault();
});

6.3. 覆盖粘贴事件

要覆盖默认的 paste 事件行为,必须添加一个 paste 事件处理程序,并且此事件处理程序必须调用 preventDefault() 来取消事件。

为了使用户代理不使用系统剪贴板中的数据更新文档,需要取消事件。

请注意,取消 paste 事件还将阻止更新文档(即,不会将任何内容粘贴到文档中)。事件处理程序将需要手动将数据粘贴到文档中。

另请注意,粘贴时,拖放数据存储模式标志为只读,因此从 paste 事件处理程序调用 setData() 不会修改插入的数据,也不会修改剪贴板上的数据。

// 覆盖粘贴到剪贴板的内容。
document.addEventListener('paste', function(e) {
    // e.clipboardData 包含即将粘贴的数据。
    if (e.clipboardData.types.indexOf('text/html') > -1) {
    var oldData = e.clipboardData.getData('text/html');
    var newData = '<b>Ha Ha!</b> ' + oldData;

    // 由于我们正在取消粘贴操作,因此需要手动
    // 将数据粘贴到文档中。
    pasteClipboardData(newData);

    // 这是防止默认粘贴操作所必需的。
    e.preventDefault();
    }
});

6.4. 强制数据类型

实现必须识别以下数据类型的本机操作系统剪贴板格式描述,以便能够使用正确的描述填充 DataTransferItemListClipboardItem 以用于粘贴事件,并在响应复制和剪切事件时在操作系统剪贴板上设置正确的数据格式。

6.4.1. 从剪贴板读取

如果剪贴板上存在相应的本机类型,则粘贴事件必须公开这些数据类型:

6.4.2. 写入剪贴板

如果在复制剪切事件期间将这些数据类型添加到 DataTransfer 对象,则必须使用相应的本机类型描述将它们放置在剪贴板上。

警告!出于安全预防措施,限制了不受信任的脚本允许写入剪贴板的数据类型。不受信任的脚本可能会通过将已知会触发本地软件中安全漏洞的数据放置在剪贴板上,从而尝试利用这些漏洞。

6.5. 可选数据类型

实现可以识别以下数据类型的本机操作系统剪贴板格式描述,以便能够使用正确的描述填充 ClipboardItem 以用于粘贴事件,并在响应复制和剪切事件时在操作系统剪贴板上设置正确的数据格式。

如果剪贴板上存在相应的本机类型,用户代理 (UA) 可以公开这些数据类型:

6.6. 未清理的数据类型

本节是非规范性的。

用户代理 (UA) 不得清理这些数据类型:

用户代理 (UA) 可以不清理这些数据类型:

可选的未清理数据类型是 Web 作者指定的MIME 类型,用户代理可以不清理这些类型。 下面列出了有效的可选的未清理数据类型

由于其隐私要求,用户代理可能不支持可选的未清理数据类型

7. 异步剪贴板 API

partial interface Navigator {
    [SecureContext, SameObject] readonly attribute Clipboard clipboard;
};

7.2. ClipboardItem 接口

typedef Promise<(DOMString or Blob)> ClipboardItemData;

[SecureContext, Exposed=Window]
interface ClipboardItem {
    constructor(record<DOMString, ClipboardItemData> items,
                optional ClipboardItemOptions options = {});

    readonly attribute PresentationStyle presentationStyle;
    readonly attribute FrozenArray<DOMString> types;

    Promise<Blob> getType(DOMString type);

    static boolean supports(DOMString type);
};

enum PresentationStyle { "unspecified", "inline", "attachment" };

dictionary ClipboardItemOptions {
    PresentationStyle presentationStyle = "unspecified";
};
clipboardItem = new ClipboardItem([items, options])
创建一个新的 ClipboardItem 对象。items 表示表示形式列表,每个表示形式都有一个MIME 类型和一个 Promise ,该 Promise 解析为与MIME 类型对应的 BlobDOMStringoptions 可用于填充其 ClipboardItemOptions, 如下例所示。
const format1 = 'text/plain';
const promise_text_blob = Promise.resolve(new Blob(['hello'], {type: format1}));
const clipboardItemInput = new ClipboardItem(
  {[format1]: promise_text_blob},
  {presentationStyle: "unspecified"});
clipboardItem.getType(type)
返回一个 Promise, 该 Promise 解析为与MIME 类型 type 对应的 Blob
clipboardItem.types
返回剪贴板项目对象中包含的MIME 类型列表。
ClipboardItem.supports(type)
如果 type 属于强制数据类型可选数据类型,则返回 true,否则返回 false。

一个剪贴板项目在概念上是用户通过调用“剪切”或“复制”命令表示希望共享的数据。一个剪贴板项目有两个用途。首先,它允许网站读取用户复制到系统剪贴板的数据。其次,它允许网站向系统剪贴板写入数据。

例如,如果用户从本机应用程序的电子表格中复制一系列单元格,则会产生一个剪贴板项目。如果用户从桌面复制一组文件,则该文件列表将由多个剪贴板项目表示。

某些平台可能支持在剪贴板上同时拥有多个剪贴板项目,而其他平台则用新的剪贴板项目替换前一个。

一个剪贴板项目有一个表示形式列表,每个表示形式都有一个关联的MIME 类型(一个MIME 类型),一个isCustom 标志(初始值为 false),指示此表示形式是否应被视为Web 自定义格式(而不是系统剪贴板的已知格式),以及数据(一个 ClipboardItemData)。

一个Web 自定义格式isCustom 设置为 true

在用户从电子表格复制单元格区域的示例中,它可以表示为图像 (image/png)、HTML 表格 (text/html) 或纯文本 (text/plain),或者 Web 自定义格式 (web text/csv)。

这些MIME 类型中的每一个都描述了同一剪贴板项目在不同保真度级别下的不同表示形式,并使剪贴板项目在粘贴期间更容易被目标应用程序使用。

将单元格区域作为图像提供,将允许用户将单元格粘贴到照片编辑应用程序中,而 text/plain 格式可供文本编辑器应用程序使用。

一个剪贴板项目有一个表示样式(一个 PresentationStyle)。 它有助于区分“粘贴”剪贴板项目的应用程序是应该在粘贴点内联插入适当表示形式的内容,还是应该将其视为附件。

仅支持粘贴单个剪贴板项目的 Web 应用程序应使用第一个剪贴板项目

write() 选择最后一个剪贴板项目

支持粘贴多个剪贴板项目的 Web 应用程序可以(例如)提供一个用户界面,预览每个剪贴板项目的内容,并允许用户选择要粘贴哪一个。 此外,应用程序应枚举它们正在粘贴的剪贴板项目MIME 类型,并根据某些特定于应用程序的算法选择最适合该应用程序的类型。 或者,应用程序可以向用户显示有关如何粘贴剪贴板项目的选项,例如“粘贴为图像”或“粘贴带格式的文本”等。

一个 ClipboardItem 对象有一个关联的剪贴板项目,它是一个剪贴板项目

一个 ClipboardItem 对象有一个关联的类型数组,它是一个 FrozenArray<DOMString>。

创建一个 ClipboardItem 对象,给定一个剪贴板项目 clipboardItem 和一个领域 realm, 请执行以下步骤:

  1. clipboardItemObject 为一个新的 ClipboardItem, 其领域为 realm

  2. clipboardItemObject剪贴板项目设置为 clipboardItem

new ClipboardItem(items, options) 构造函数步骤如下:

  1. 如果 items 为空,则抛出 TypeError

  2. 如果 options 为空,则设置 options["presentationStyle"] = "unspecified"。

  3. 此对象剪贴板项目设置为一个新的剪贴板项目

  4. 此对象剪贴板项目表示样式设置为 options["presentationStyle"]。

  5. types 为一个 DOMString 列表。

  6. 对于 items 中的每个 (key, value):

    1. representation 为一个新的表示形式

    2. isCustomfalse

    3. 如果 key `"web "` 前缀开头,则

      1. 移除 `"web "` 前缀并将剩余字符串赋给 key

      2. 设置 isCustomtrue

    4. representationisCustom 标志设置为 isCustom

    5. mimeType 为给定 key 解析 MIME 类型的结果。

    6. 如果 mimeType 为失败,则抛出 TypeError

    7. 如果此对象剪贴板项目表示形式列表 包含一个表示形式,其MIME 类型mimeType 且其 [representation/isCustom] 为 isCustom,则抛出 TypeError

    上述步骤可防止用户代理已知的 MIME 类型与作者希望视为自定义类型的 MIME 类型之间发生冲突。例如,作者的项目列表可能包含 "text/html" 以及 "web text/html" 的表示形式。

    1. representationMIME 类型设置为 mimeType

    2. representation数据设置为 value

    3. representation 附加到此对象剪贴板项目表示形式列表

    4. mimeTypeString 为使用 mimeType 序列化 MIME 类型的结果。

    5. 如果 isCustomtrue,则在 mimeTypeString 前添加 `"web "` 前缀。

    6. mimeTypeString 添加到 types

  7. 此对象类型数组设置为从 types 运行创建冻结数组的结果。

7.2.1. presentationStyle

presentationStyle getter 的步骤是返回此对象剪贴板项目表示样式

7.2.2. types

types getter 的步骤是返回此对象类型数组

7.2.3. getType(type)

此方法必须运行以下步骤:

  1. realm此对象相关领域

  2. isCustomfalse

  3. 如果 type `"web "` 前缀开头,则:

    1. 移除 `"web "` 前缀并将剩余字符串赋给 type

    2. 设置 isCustomtrue

  4. mimeType 为给定 type 解析 MIME 类型的结果。

  5. 如果 mimeType 为失败,则抛出 TypeError

  6. itemTypeList此对象剪贴板项目表示形式列表

  7. prealm 中的一个新的 promise

  8. 对于 itemTypeList 中的每个 representation

    1. 如果 representationMIME 类型mimeType 并且 representationisCustomisCustom,则:

      1. representationDataPromiserepresentation数据

      2. 响应 representationDataPromise

        1. 如果 representationDataPromise 以值 v 完成,则:

          1. 如果 v 是一个 DOMString, 则执行以下步骤:

            1. dataAsBytesUTF-8 编码 v 的结果。

            2. blobData 为一个使用 dataAsBytes 创建的 Blob, 其 type 设置为 mimeType,并序列化

            3. blobData 解析 p

          2. 如果 v 是一个 Blob, 则执行以下步骤:

            1. v 解析 p

        2. 如果 representationDataPromise 被拒绝,则:

          1. realm 中用 "NotFoundError" DOMException 拒绝 p

            Web 开发人员可能对潜在的拒绝原因感兴趣。

      3. 返回 p

  9. realm 中用 "NotFoundError" DOMException 拒绝 p

  10. 返回 p

7.2.4. supports(type)

此方法必须运行以下步骤:

  1. 如果 type 属于强制数据类型可选数据类型,则返回 true。

  2. 否则,返回 false。

7.3. 剪贴板接口

typedef sequence<ClipboardItem> ClipboardItems;

[SecureContext, Exposed=Window]
interface Clipboard : EventTarget {
    Promise<ClipboardItems> read(optional ClipboardUnsanitizedFormats formats = {});
    Promise<DOMString> readText();
    Promise<undefined> write(ClipboardItems data);
    Promise<undefined> writeText(DOMString data);
};

dictionary ClipboardUnsanitizedFormats {
    sequence<DOMString> unsanitized;
};

剪贴板 接口的一些方法接受或返回多个 ClipboardItem 对象。但是,并非所有平台都支持多个剪贴板项目;在此类平台上,以下算法将忽略传递给 write() 的第一个 ClipboardItem 对象之后的任何对象,并且 read()readText() 仅从操作系统获取一个剪贴板项目。

一个 剪贴板项目 对象是一个序列,包含剪贴板项目

Web 作者需要创建一个 data,它是一个 ClipboardItem 数组,以便使用 write(data) 方法将内容写入系统剪贴板read() 返回一个 Promise, 该 Promise 解析为表示系统剪贴板数据内容的剪贴板项目对象。

unsanitized 是一个序列,包含 DOMString, 对应于作者希望被视为可选的未清理数据类型MIME 类型

用户代理可能不支持 unsanitized 选项。Web 作者不应假定 unsanitized 中列出的 MIME 类型的内容将是未清理的,因为在某些隐私模式下可能不允许此选项。

剪贴板任务源是在读取或写入系统剪贴板数据时触发的。

7.3.1. read(formats)

read(formats) 方法必须执行以下步骤:
  1. realm此对象相关领域

  2. prealm 中的一个新的 promise

  3. 如果 formats 不为空,则:

    1. 对于 formats["unsanitized"] 中的每个 format

      1. 如果 format 不在可选的未清理数据类型中,则在 realm 中用 format "NotAllowedError" DOMException 拒绝 p

  4. 并行运行以下步骤:

    1. r 为运行检查剪贴板读取权限的结果。

    2. 如果 r 为 false,则:

      1. 权限任务源上,给定 realm全局对象将一个全局任务排队,以在 realm 中用 "NotAllowedError" DOMException 拒绝 p

      2. 中止这些步骤。

    3. data系统剪贴板数据的副本。

    4. items 为一个序列<剪贴板项目>。

    5. 对于 data 中的每个 systemClipboardItem

      1. item 为一个新的剪贴板项目

      2. 对于 systemClipboardItem 中的每个 systemClipboardRepresentation

        1. mimeType 为给定 systemClipboardRepresentation名称运行从操作系统特定格式获取已知 MIME 类型算法的结果。

        2. 如果 mimeType 为 null,则继续此循环。

        3. representation 为一个新的表示形式

        4. representationMIME 类型设置为 mimeType

        5. isUnsanitizedfalse

        6. 如果 formats 不为空,则:

          1. 对于 formats["unsanitized"] 中的每个 format

            1. 如果 format 等于MIME 类型,则将 isUnsanitized 设置为 true。

        7. systemClipboardRepresentation数据解析 representation数据

          在作者调用 getType 后,应该可以从系统剪贴板异步读取数据,但是,这组步骤意味着数据将在读取时提供。

        8. 用户代理可以清理 representation数据,除非 representationMIME 类型的本质是 "image/png"(应保持未清理以保留元数据),或者如果它满足以下条件:

          1. representationMIME 类型在可选的未清理数据类型列表中。

          2. isUnsanitized 为 true。

        9. representation 附加到 item表示形式列表

        10. isUnsanitized 设置为 false

      3. 如果 item表示形式列表的大小大于 0,则将 item 附加到 items

    6. 如果 items 的大小 > 0,则:

      1. firstItemitems[0]

      2. 给定 firstItem 运行读取 Web 自定义格式算法。

    7. 否则:

      1. customItem 为一个新的剪贴板项目

      2. 给定 customItem 运行读取 Web 自定义格式算法。

      3. 如果 customItem表示形式列表的大小大于 0,则将 customItem 附加到 items

    8. 剪贴板任务源上,给定 realm全局对象将一个全局任务排队,以执行以下步骤:

      1. clipboardItems 为一个序列<ClipboardItem>。

      2. 对于 items 中的每个剪贴板项目 underlyingItem

        1. clipboardItem 为给定 underlyingItemrealm 运行创建 ClipboardItem 对象的步骤的结果。

        2. clipboardItem 附加到 clipboardItems

      3. clipboardItems 解析 p

  5. 返回 p

const items = await navigator.clipboard.read();
const textBlob = await items[0].getType("text/plain");
const text = await (new Response(textBlob)).text();

7.3.2. readText()

readText() 方法必须执行以下步骤:
  1. realm此对象相关领域

  2. prealm 中的一个新的 promise

  3. 并行运行以下步骤:

    1. r 为运行检查剪贴板读取权限的结果。

    2. 如果 r 为 false,则:

      1. 权限任务源上,给定 realm全局对象将一个全局任务排队,以在 realm 中用 "NotAllowedError" DOMException 拒绝 p

      2. 中止这些步骤。

    3. data系统剪贴板数据的副本。

      某些操作系统包含多个剪贴板(例如 Linux 中的“primary”、“secondary”、“selection”)。定义从哪个剪贴板读取数据。

      添加已清理副本的定义。

    4. 剪贴板任务源上,给定 realm全局对象将一个全局任务排队,以执行以下步骤:

      1. 对于 data 中的每个 systemClipboardItem

        1. 对于 systemClipboardItem 中的每个 systemClipboardRepresentation

          1. mimeType 为给定 systemClipboardRepresentation名称运行从操作系统特定格式获取已知 MIME 类型算法的结果。

          2. 如果 mimeType 为 null,则继续此循环。

          3. representation 为一个新的表示形式

          4. 如果 representationMIME 类型本质是 "text/plain",则:

            1. representationMIME 类型设置为 mimeType

            2. representationDataPromiserepresentation数据

            3. 响应 representationDataPromise

              1. 如果 representationDataPromise 以值 v 完成,则:

                1. 如果 v 是一个 DOMString, 则执行以下步骤:

                  1. v 解析 p

                  2. 返回 p

                2. 如果 v 是一个 Blob, 则执行以下步骤:

                  1. stringUTF-8 解码 v 的底层字节序列的结果。

                  2. string 解析 p

                  3. 返回 p

              2. 如果 representationDataPromise 被拒绝,则:

                1. realm 中用 "NotFoundError" DOMException 拒绝 p

                2. 返回 p

      2. realm 中用 "NotFoundError" DOMException 拒绝 p

      3. 返回 p

navigator.clipboard.readText().then(function(data) {
    console.log("你的字符串: ", data);
});

7.3.3. write(data)

write(data) 方法必须执行以下步骤:
  1. realm此对象相关领域

  2. prealm 中的一个新的 promise

  3. 并行运行以下步骤:

    1. r 为运行检查剪贴板写入权限的结果。

      clipboard-write 已在 https://github.com/w3c/clipboard-apis/pull/164 中移除。

    2. 如果 r 为 false,则:

      1. 权限任务源上,给定 realm全局对象将一个全局任务排队,以在 realm 中用 "NotAllowedError" DOMException 拒绝 p

      2. 中止这些步骤。

    3. 剪贴板任务源上,给定 realm全局对象将一个全局任务排队,以执行以下步骤:

      1. itemListcleanItemList 为一个空的序列<Blob>。

      2. dataList 为一个序列<ClipboardItem>。

      3. 如果 data大小大于 1,并且当前操作系统不支持系统剪贴板上的多个本机剪贴板项目,则将 data[0] 添加到 dataList,否则,将 dataList 设置为 data

        data 包含多个项目并且操作系统支持多个本机剪贴板项目时,当前算法会按顺序将项目写入系统剪贴板,而不是集体写入。

      4. 对于 dataList 中的每个 clipboardItem

        1. 对于 clipboardItem剪贴板项目表示形式列表中的每个 representation

          1. representationDataPromiserepresentation数据

          2. 响应 representationDataPromise

            1. 如果 representationDataPromise 以值 v 完成,则:

              1. 如果 v 是一个 DOMString, 则执行以下步骤:

                1. dataAsBytesUTF-8 编码 v 的结果。

                2. blobData 为一个使用 dataAsBytes 创建的 Blob, 其 type 设置为 representationMIME 类型

                3. blobData 添加到 itemList

              2. 如果 v 是一个 Blob, 则将 v 添加到 itemList

            2. 如果 representationDataPromise 被拒绝, 则:

              1. realm 中用 "NotAllowedError" DOMException 拒绝 p

              2. 中止这些步骤。

        2. 对于 itemList 中的每个 blob

          1. typeblobtype

          2. 如果 type 不在强制数据类型可选数据类型列表中,则在 realm 中用 "NotAllowedError" DOMException 拒绝 p 并中止这些步骤。

          3. cleanItemblob 的一个可选的已清理副本。

            添加已清理副本的定义。

          4. 如果尝试了清理但未成功完成,则执行以下步骤:

            1. realm 中用 "NotAllowedError" DOMException 拒绝 p

            2. 中止这些步骤。

          5. cleanItem 附加到 cleanItemList

        3. optionclipboardItem剪贴板项目表示样式

        4. 使用 cleanItemListoption 将 blob 和选项写入剪贴板

      5. 解析 p

  4. 返回 p

var data = [new ClipboardItem({ "text/plain": Promise.resolve(new Blob(["文本数据"], { type: "text/plain" })) })];
navigator.clipboard.write(data).then(function() {
    console.log("已成功复制到剪贴板!");
}, function() {
    console.error("无法写入剪贴板。 :-(");
});

7.3.4. writeText(data)

writeText(data) 方法必须执行以下步骤:
  1. realm此对象相关领域

  2. prealm 中的一个新的 promise

  3. 并行运行以下步骤:

    1. r 为运行检查剪贴板写入权限的结果。

      clipboard-write 已在 https://github.com/w3c/clipboard-apis/pull/164 中移除。

    2. 如果 r 为 false,则:

      1. 权限任务源上,给定 realm全局对象将一个全局任务排队,以在 realm 中用 "NotAllowedError" DOMException 拒绝 p

      2. 中止这些步骤。

    3. 剪贴板任务源上,给定 realm全局对象将一个全局任务排队,以执行以下步骤:

      1. itemList 为一个空的序列<Blob>。

      2. textBlob 为一个新创建的 Blob, 其:type 属性设置为 "text/plain;charset=utf-8",并且 其底层字节序列设置为 dataUTF-8 编码

        注意:在 Windows 上,在创建 textBlob 之前,将 data 中的 `\n` 字符替换为 `\r\n`。

      3. textBlob 添加到 itemList

      4. option 设置为 "unspecified"。

      5. 使用 itemListoption 将 blob 和选项写入剪贴板

      6. 解析 p

  4. 返回 p

await navigator.clipboard.writeText("你好,伙伴!");

8. 剪贴板操作

本节定义剪贴板操作和事件分发的处理模型。

每个剪贴板操作都有两个标志,称为脚本触发脚本可访问剪贴板

如果操作因脚本而运行(例如 document.execCommand() 调用),则设置 脚本触发 标志。未来与剪贴板交互的脚本 API 也应使用这些操作,并且必须相应地设置 脚本触发标志。

脚本可访问剪贴板 标志设置如下:

  1. 如果操作是复制剪切,并且脚本线程允许修改剪贴板,则

    1. 设置操作的脚本可访问剪贴板标志

  2. 如果操作是粘贴,并且脚本线程允许从剪贴板读取,则

    1. 设置操作的脚本可访问剪贴板标志。

8.1. 复制操作

复制操作包括以下步骤:

  1. 如果设置了脚本触发标志,则

    1. 如果未设置脚本可访问剪贴板标志,则

      1. 从复制操作返回 false,终止此算法

  2. 触发一个名为 copy 的剪贴板事件

  3. 如果事件未被取消,则

    1. 将选定的内容(如有)复制到剪贴板。当选择网页中的内容时,实现创建备用的 text/html 和 text/plain 剪贴板格式。

    2. 触发一个名为 clipboardchange 的剪贴板事件

  4. 否则,如果事件被取消,则

    1. 调用将内容写入剪贴板算法, 传递 DataTransferItemList 列表 items、 一个 clear-was-called 标志和一个 types-to-clear 列表。

  5. 从复制操作返回 true

8.2. 剪切操作

剪切操作包括以下步骤:

  1. 如果设置了脚本触发标志,则

    1. 如果未设置脚本可访问剪贴板标志,则

      1. 从剪切操作返回 false,终止此算法

  2. 触发一个名为 cut 的剪贴板事件

  3. 如果事件未被取消,则

    1. 如果在启用了剪切的可编辑上下文中存在选区,则

      1. 将选定的内容(如有)复制到剪贴板。当选择网页中的内容时,实现创建备用的 text/html 和 text/plain 剪贴板格式。

      2. 从文档中删除选区的内容并折叠选区。

      3. 触发一个名为 clipboardchange 的剪贴板事件

      4. 将由于修改而应触发的任何事件排队,有关详细信息,请参阅§ 5.3 与其他脚本和事件的集成

    2. 否则,如果没有选区或上下文不可编辑,则

      1. 返回 false

  4. 否则,如果事件被取消,则

    1. 调用将内容写入剪贴板算法, 传递 DataTransferItemList 列表 items、 一个 clear-was-called 标志和一个 types-to-clear 列表。

    2. 触发一个名为 clipboardchange 的剪贴板事件

  5. 从剪切操作返回 true

8.3. 粘贴操作

对于粘贴操作,脚本可访问剪贴板标志取决于实现特定的权限机制,用于确定哪些站点或应用可以从剪贴板读取。当脚本触发粘贴操作时,实现不得在未经用户许可的情况下提供剪贴板内容。如果尚未授予权限,则权限提示必须包括与脚本线程关联的文档的主机名。

粘贴操作包括以下步骤:

  1. 如果设置了脚本触发标志,则

    1. 如果未设置脚本可访问剪贴板,则

      1. 从粘贴操作返回 false,终止此算法

  2. 触发一个名为 paste 的剪贴板事件

  3. 如果事件未被取消,则

    1. 如果在启用了粘贴的可编辑上下文中存在选区或光标,则

      1. 将剪贴板上找到的最合适的内容(如有)插入到上下文中。

      2. 将由于修改而应触发的任何事件排队,有关详细信息,请参阅§ 5.3 与其他脚本和事件的集成

    2. 否则

      1. 返回 false

  4. 否则,如果事件被取消

    1. 返回 false

  5. 从操作返回 true

9. Permissions API 集成

[permissions] API 为网站提供了一种统一的方式来访问强大的功能,例如剪贴板。它允许网站向用户请求权限并查询它们拥有的权限。

对于剪贴板,定义了一个权限:"clipboard-write"

注意:剪贴板权限目前仅适用于异步剪贴板 API。 此规范的未来版本可能会更新以将此权限应用于其他剪贴板交互。

这些剪贴板权限是强大的功能,与权限相关的算法和类型定义如下:

权限描述符类型
dictionary ClipboardPermissionDescriptor : PermissionDescriptor {
    boolean allowWithoutGesture = false;
};

有 4 个剪贴板权限:

具有以下关系:

虽然用户代理必须支持本规范中描述的 ClipboardPermissionDescriptor, 但它们当然保留对默认设置以及如何(或是否)向用户公开这些设置的完全控制权。

一个希望对剪贴板具有单独的用户可设置写入控件并且始终需要用户手势的用户代理将按如下方式处理每个描述符:

9.1. 剪贴板读取权限

9.1.1. 检查剪贴板读取权限

  1. 如果相关全局对象此对象具有瞬时激活,则令 hasGesture 为 true,否则为 false。

  2. 如果 hasGesture 为 true,则:

    1. 如果当前脚本是由于用户与用户代理或操作系统创建的“粘贴”元素交互而运行的,则返回 true。

  3. 返回 false。

9.2. 剪贴板写入权限

9.2.1. 检查剪贴板写入权限

  1. writeWithoutGesture{ name: "clipboard-write", allowWithoutGesture: true } 权限的权限状态

  2. 如果 writeWithoutGesturegranted, 则返回 true。

  3. 如果相关全局对象此对象具有瞬时激活,则令 hasGesture 为 true,否则为 false。

  4. 如果 hasGesture 为 true,则:

    1. 如果当前脚本是由于用户与用户代理或操作系统创建的“剪切”或“复制”元素交互而运行的,则令 systemCopy 为 true。

    2. 如果 systemCopy 为 true,则返回 true。

    3. 返回请求使用权限 { name: "clipboard-write", allowWithoutGesture: false } 权限的结果。

      注意:用户代理可以选择请求一个更强的权限,该权限将隐式更新此权限。

  5. 返回请求使用权限 { name: "clipboard-write", allowWithoutGesture: true } 权限的结果。

10. 安全注意事项

允许作者更改用户复制的内容,或自动复制从未被选中的内容,以及允许无限制地调用粘贴信息,这些都可能引发各种安全问题。

一些示例场景包括:

10.1. 粘贴 HTML 和多部分数据

本节是非规范性的。

粘贴格式化或多部分数据存在某些安全风险。

为了确定使用哪些策略,我们考虑的因素有:

以下是场景和可能的安全策略概述:

数据来源 脚本来源 规则
源自在线资源 与数据相同 不清理 HTML。不访问任何本地文件。
不同来源 可选地清理内容。不访问任何本地文件。
源自本地应用程序 任何 不清理 HTML。授予对本地文件的访问权限

一些实现通过在粘贴富文本时默认剥离潜在的恶意内容(例如 SCRIPT 元素和 javascript: 链接)来降低与粘贴富文本相关的风险,但允许粘贴事件处理程序检索和处理原始的、未清理的数据。

10.2. 通用安全策略

实现不得下载引用的在线资源,或在 files 列表或 DataTransferItemList 中公开其内容。

如果剪贴板上的数据不是来自本地应用程序,则实现不得授予对任何引用的本地文件的访问权限。例如,如果数据包含 <img src="file://localhost/example.jpg"> 但数据的来源是在线资源,则实现不得将 example.jpg 的条目添加到 clipboardData.items 列表中。

10.3. 转码图像

为防止恶意图像数据被放置在剪贴板上,可以对图像数据进行转码以生成图像的安全版本。这可以防止网站试图利用其他应用程序中的安全漏洞。

实现不应转码从剪贴板读取的图像。转码图像可能会丢失重要的元数据(例如图像的物理分辨率)。 这也与可以与网站共享图像的其他方法(例如 `<input type=file>`)一致。

10.4. 滋扰注意事项

脚本可以使用 DataTransfer API 通过更改复制和剪切事件中系统剪贴板上的数据来骚扰和迷惑用户。本规范不试图阻止此类滋扰,但实现可能会添加额外的限制。

实现必须妥善处理试图在剪贴板上放置过多数据的脚本。

11. 隐私注意事项

由于这些 API 提供了对用户剪贴板数据的访问权限,因此存在严重的隐私问题,因为剪贴板可能包含个人身份信息 (PII),例如姓名、地址或密码。

通常,用户代理必须确保不受信任的脚本无法通过这些 API 不受控制地访问用户的剪贴板数据。

11.1. 隐私和剪贴板事件 API

剪贴板事件 API 允许在剪贴板事件处理程序上下文中运行的脚本访问系统剪贴板的副本,并可能修改写入剪贴板的数据。

用户代理应注意以下有关保护剪贴板事件 API 访问的数据的要求:

尽管剪贴板事件 API 不受剪贴板权限的保护,但用户代理可以选择提供一种方法,让用户禁用此 API 或配置允许哪些站点访问它。

11.2. 隐私和异步剪贴板 API

异步剪贴板 API 是一项强大的功能,因为它允许从任何脚本访问剪贴板数据(访问不限于剪贴板事件处理程序),并且可以在没有用户提供手势的情况下访问数据。

为帮助防止滥用,此 API 不得可用,除非脚本在具有焦点的文档上下文中执行。

11.2.1. 隐私和剪贴板权限

剪贴板权限控制对此 API 的访问,但用户代理可以选择权限默认值以及用户可以设置哪些权限设置。例如,用户代理可以选择仅在存在用户手势时才允许访问异步剪贴板 API,并始终拒绝脚本在没有手势的情况下访问的请求。

用户代理可以选择让此权限在用户授予权限后的某个时间自动过期,例如,通过让权限过期:

11.3. 其他隐私问题

如果用户代理允许使用 document.execCommand("paste") 读取剪贴板数据,则用户代理必须确保用户已明确允许进行该访问。

12. 致谢

本节为非规范性内容

编辑们感谢前任编辑们所做的贡献,他们帮助本规范经历了各种会议和邮件列表讨论,使其达到目前的状态。

编辑们也感谢微软的 Data Transfer 功能文档 [MICROSOFT-CLIP-OP] 以及 [HTML5] 规范的早期草案在知识上的启发。 我们也感谢 Paul Libbrecht 提供的“安全复制和粘贴”草案(此草案已无法在网络上找到)。

最后,我们要感谢以下人员所做的贡献:

Adam Barth, Shawn Carnell, Daniel Cheng, Daniel Dardailler, Domenic Denicola, Al Gilman, James Graham, James Greene, Ian Hickson, Darwin Huang, Lachlan Hunt, Philip Jägenstedt, Anne van Kesteren, Marijn Kruisselbrink, Aaron Leventhal, Jim Ley, Paul Libbrecht, "Martijn", Glenn Maynard, Chris Mills, ms2ger, Ryosuke Niwa, Robert O’Callahan, Dave Poehlman, "ROBO Design", Janina Sajka, Rich Schwerdtfeger, Jonas Sicking, Maciej Stachowiak, Mihai Sucan, Dmitry Titov, Ojan Vafai, Tarquin Wilton-Jones, Tom Wlodkowski, Bo Cupp, mbrodesser 和 Boris Zbarsky。

附录 A:算法

将内容写入剪贴板

输入

items,一个要写入的项目的 DataTransferItemList 列表

clear-was-called,一个布尔值

types-to-clear,一个列表

输出

  1. 如果 items 列表不为空,则

    1. 清除剪贴板

    2. 对于列表中的每个部分,

      1. 如果数据类型是 text/plain,则

        1. 确保编码根据操作系统和区域设置约定是正确的

        2. 根据平台约定规范化行尾

        3. 使用适当的操作系统剪贴板格式描述将文本放置在剪贴板上

      2. 否则,如果数据类型是强制数据类型列表中列出的类型,则

        1. 使用适当的操作系统剪贴板格式描述将部分放置在剪贴板上

      3. 否则

        1. 这留给实现...

          将事情留给实现是不好的。这里应该发生什么?

          注意:由于操作系统剪贴板实现的限制,脚本不应假定自定义格式可用于系统上的其他应用程序。例如,在 Microsoft Windows 中可以注册的自定义剪贴板格式数量有限。虽然可以为 setData() 的 type 参数使用任何字符串,但强烈建议坚持使用强制数据类型

  2. 否则,items 列表为空。按照以下步骤确定是否清除剪贴板:

    1. 如果项目列表为空且 clear-was-called 标志为 true,则

      1. 如果 types-to-clear 列表为空,则

        1. 清除剪贴板

      2. 否则

        1. 以操作系统和实现特定的方式从剪贴板中删除 types-to-clear 列表中的类型

          “从剪贴板中删除特定类型”功能存在风险。它似乎并不那么重要,而且尚不清楚它是否可以在相关平台上轻松实现。

将 blob 和选项写入剪贴板

输入

items,一个 序列<Blob>

presentationStyle,一个剪贴板项目表示样式

输出

  1. webCustomFormats 为一个 序列<Blob>。

  2. 对于 items 中的每个 item

    1. formatString 为运行特定于操作系统的已知格式的结果,给定 itemtype

    2. 如果 formatString 为空,则执行以下步骤:

      1. webCustomFormatStringitemtype

      2. webCustomFormat 为一个空的 type

      3. 如果 webCustomFormatString `"web "` 前缀开头,则移除 `"web "` 前缀并将剩余字符串存储在 webMimeTypeString 中。

      4. webMimeType解析 MIME 类型的结果,给定 webMimeTypeString

      5. 如果 webMimeType 失败,则中止所有步骤。

      6. webCustomFormattype本质等于 webMimeType

      7. itemtype 设置为 webCustomFormat

      8. webCustomFormat 附加到 webCustomFormats

    3. payloadUTF-8 解码 item 的底层字节序列的结果。

    4. 使用 formatString 作为本机剪贴板格式,将 payloadpresentationStyle 插入到系统剪贴板中。

    某些操作系统包含多个剪贴板(例如 Linux 中的“primary”、“secondary”、“selection”)。定义数据写入到其中的哪一个。

  3. 给定 webCustomFormats写入 Web 自定义格式

特定于操作系统的已知格式

输入

mimeType,一个 type

输出

wellKnownFormat,一个平台特定的字符串类型。在 Mac 上是 NSPasteboardType,在 Windows 上是 LPCWSTR,在 Linux 上是 const char*。

对于 Windows,请参阅 https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats 和 https://docs.microsoft.com/en-us/windows/win32/dataxchg/about-atom-tables?redirectedfrom=MSDN 对于 Mac,请参阅 https://developer.apple.com/documentation/appkit/nspasteboardtype

  1. wellKnownFormat 为一个空字符串。

  2. 如果 mimeType本质是 "text/plain",则

    在 Windows 上,遵循以下描述的约定:

    1. 将 CF_UNICODETEXT 分配给 wellKnownFormat

    在 MacOS 上,遵循以下描述的约定:

    1. 将 NSPasteboardTypeString 分配给 wellKnownFormat

    在 Linux、ChromeOS 和 Android 上,遵循以下描述的约定:

    1. 将 "text/plain" 分配给 wellKnownFormat

  3. 否则,如果 mimeType本质是 "text/html",则

    在 Windows 上,遵循以下描述的约定:

    1. 将 CF_HTML 分配给 wellKnownFormat

    在 MacOS 上,遵循以下描述的约定:

    1. 将 NSPasteboardTypeHTML 分配给 wellKnownFormat

    在 Linux、ChromeOS 和 Android 上,遵循以下描述的约定:

    1. 将 "text/html" 分配给 wellKnownFormat

  4. 否则,如果 mimeType本质是 "image/png",则

    在 Windows 上,遵循以下描述的约定:

    1. 将 "PNG" 分配给 wellKnownFormat

    在 MacOS 上,遵循以下描述的约定:

    1. 将 NSPasteboardTypePNG 分配给 wellKnownFormat

    在 Linux、ChromeOS 和 Android 上,遵循以下描述的约定:

    1. 将 "image/png" 分配给 wellKnownFormat

  5. Else, if mimeType’s essence is "image/svg+xml", then

    在 Windows 上,遵循以下描述的约定:

    1. 将 CFSTR_MIME_SVG_XML 分配给 wellKnownFormat

    在 MacOS 上,遵循以下描述的约定:

    1. 将 UTTypeSVG 分配给 wellKnownFormat

    在 Linux、ChromeOS 和 Android 上,遵循以下描述的约定:

    1. 将 "image/svg+xml" 分配给 wellKnownFormat

  6. 返回 wellKnownFormat

从特定于操作系统的格式获取已知 MIME 类型

输入

osFormatName,一个平台特定的字符串类型。在 Mac 上是 NSPasteboardType,在 Windows 上是 LPCWSTR,在 Linux 上是 const char*。

输出

mimeType,一个 MIME 类型

对于 Windows,请参阅 https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats 和 https://docs.microsoft.com/en-us/windows/win32/dataxchg/about-atom-tables?redirectedfrom=MSDN 对于 Mac,请参阅 https://developer.apple.com/documentation/appkit/nspasteboardtype

在 Windows 上,遵循以下描述的约定:

  1. 如果 osFormatName 是 "UnicodeText",则将 mimeTypeString 设置为 "text/plain"。

  2. 否则,如果 osFormatName 是 "HTML Format",则将 mimeTypeString 设置为 "text/html"。

  3. 否则,如果 osFormatName 是 "PNG",则将 mimeTypeString 设置为 "image/png"。

  4. 否则,如果 osFormatName 是 CFSTR_MIME_SVG_XML,则将 mimeTypeString 设置为 "image/svg+xml"。

在 MacOS 上,遵循以下描述的约定:

  1. 如果 osFormatName 是 NSPasteboardTypeString,则将 mimeTypeString 设置为 "text/plain"。

  2. 否则,如果 osFormatName 是 NSPasteboardTypeHTML,则将 mimeTypeString 设置为 "text/html"。

  3. 否则,如果 osFormatName 是 NSPasteboardTypePNG,则将 mimeTypeString 设置为 "image/png"。

  4. 否则,如果 osFormatName 是 UTTypeSVG,则将 mimeTypeString 设置为 "image/svg+xml"。

在 Linux、ChromeOS 和 Android 上,遵循以下描述的约定:

  1. 如果 osFormatName 是 "text/plain",则将 mimeTypeString 设置为 "text/plain"。

  2. 否则,如果 osFormatName 是 "text/html",则将 mimeTypeString 设置为 "text/html"。

  3. 否则,如果 osFormatName 是 "image/png",则将 mimeTypeString 设置为 "image/png"。

  4. 否则,如果 osFormatName 是 "image/svg+xml",则将 mimeTypeString 设置为 "image/svg+xml"。

  1. mimeType解析 MIME 类型的结果,给定 mimeTypeString

  2. 返回 mimeType

读取 Web 自定义格式

输入

item,一个剪贴板项目

  1. webCustomFormatMap特定于操作系统的自定义映射名称

  2. 系统剪贴板读取 webCustomFormatMap

    更详细地说明读取 webCustomFormatMap 的过程。

  3. 如果 webCustomFormatMap 为空,则返回 item

  4. webCustomFormatMapString 为从 webCustomFormatMap 反序列化得到的 JSON 字符串。

    注意:需要一个 JSON 读取器来从 webCustomFormatMap 反序列化内容。

  5. 对于 webCustomFormatMapString 中的每个 (key, value):

    1. mimeType 为给定 key 解析 MIME 类型的结果。

    2. 如果 mimeType 解析失败,则继续循环。

    3. representation 为一个新的表示

    4. representationMIME 类型设置为 mimeType

    5. representationisCustom 标志设置为 true

    6. 给定 value,从系统剪贴板读取 webCustomFormat

    7. 如果读取成功,则将 representation数据设置为从系统剪贴板获取的数据,否则继续循环。

    8. representation 附加到 item表示列表

写入 Web 自定义格式

输入

items,一个 序列<Blob>

  1. idx 为一个初始化为 0 的数字。

  2. webCustomFormatMap特定于操作系统的自定义映射名称

  3. webCustomFormatMapString 为一个空的 JSON 字符串。

  4. 对于 items 中的每个 item

    1. webCustomFormat特定于操作系统的自定义名称

    2. webCustomFormatIdx 为将 idx 附加到 webCustomFormat 的结果。

    3. 使用 JSON 序列化器将 itemtype 作为键,webCustomFormatIdx 作为值插入到 webCustomFormatMapString 中。

      注意:需要一个 JSON 写入器将内容序列化到 webCustomFormatMapString 中。

    4. 使用 webCustomFormatIdx 作为格式,将 item 插入到系统剪贴板中。

    5. 递增 idx

    6. 如果 idx 大于 100,则跳出此循环。

  5. 使用 webCustomFormatMap 作为格式,将 webCustomFormatMapString 插入到系统剪贴板中。

特定于操作系统的自定义映射名称

输出

webCustomFormatMap,一个字符串

在 Windows 上,遵循以下描述的约定:

  1. 将 "Web Custom Format Map" 分配给 webCustomFormatMap

  2. 返回 webCustomFormatMap

在 MacOS 上,遵循以下描述的约定:

  1. 将 "org.w3.web-custom-format.map" 分配给 webCustomFormatMap

  2. 返回 webCustomFormatMap

在 Linux、ChromeOS 和 Android 上,遵循以下描述的约定:

  1. 将 "application/web;type=\"custom/formatmap\"" 分配给 webCustomFormatMap

  2. 返回 webCustomFormatMap

特定于操作系统的自定义名称

输出

webCustomFormat,一个字符串

在 Windows 上,遵循以下描述的约定:

  1. 将 "Web Custom Format" 分配给 webCustomFormat

  2. 返回 webCustomFormat

在 MacOS 上,遵循以下描述的约定:

  1. 将 "org.w3.web-custom-format.type-" 分配给 webCustomFormat

  2. 返回 webCustomFormat

在 Linux、ChromeOS 和 Android 上,遵循以下描述的约定:

  1. 将 "application/web;type="custom/format" 分配给 webCustomFormat

  2. 返回 webCustomFormat

触发剪贴板事件

输入

e,要触发的 ClipboardEvent

输出

  1. clear-was-calledfalse

  2. types-to-clear 为一个空列表

  3. clipboard-event-data 为一个新的 DataTransfer 对象,其 items 列表为空。

  4. clipboard-entry 为当前剪贴板内容的序列号,如果操作系统剪贴板不支持序列号,则为 null

  5. 如果事件由用户代理生成,则令 trustedtrue,否则为 false

  6. 按如下方式设置 target

    1. 如果上下文是可编辑的,则

      1. target 设置为包含文档顺序中可见选区或光标开头的元素,如果没有可见选区或光标,则设置为body 元素

    2. 否则,如果上下文不可编辑,则

      1. target 设置为焦点节点,如果没有节点具有焦点,则设置为body 元素

  7. 按如下方式处理事件:

    1. 如果 e 是 "paste",则

      1. clipboard-event-data 的内部拖放数据存储模式标志设置为只读

      2. 如果 trustedtrue,或者实现配置为授予脚本生成的事件对操作系统剪贴板的读取权限

        1. 对于操作系统剪贴板上的每个 clipboard-part,执行以下步骤:

          1. 如果 clipboard-part 包含纯文本,则

            1. 确保文本使用脚本引擎内部使用的编码

            2. new-data 为一个新的 DataTransferItem, 其拖放数据项种类设置为 string拖放数据项类型字符串设置为 text/plain

            3. new-data 的数据设置为纯文本。

            4. new-data 添加到 clipboard-event-dataitems

          2. 如果 clipboard-part 表示文件引用,则对于每个文件引用:

            1. 确定引用文件的 MIME 类型

            2. new-data 为一个新的 DataTransferItem, 其拖放数据项种类设置为 file拖放数据项类型字符串设置为相应的 MIME 类型,如果文件类型未知,则设置为 application/octet-stream

            3. new-data 的数据设置为文件引用数据。

            4. new-data 添加到 clipboard-event-dataitems

          3. 如果 clipboard-part 包含 HTML 或 XHTML 格式的文本(根据操作系统描述此类剪贴板格式的约定),则

            1. 如果实现支持粘贴 HTML,则实现必须通过使用 clipboard-partclipboard-event-data 调用处理 html 粘贴事件来处理标记。

          4. 如果 clipboard-part 包含其他受支持的二进制或基于文本的格式的数据(请参阅强制数据类型),则

            1. 确定数据的 MIME 类型

            2. new-data 为一个新的 DataTransferItem, 其拖放数据项种类设置为 file拖放数据项类型字符串设置为相应的 MIME 类型

            3. new-data 的数据设置为二进制或基于文本的数据。

            4. new-data 添加到 clipboard-event-dataitems

      3. 更新 clipboard-event-datafiles 属性以匹配 clipboard-event-dataitems 中的条目。

      4. 更新 clipboard-event-datatypes 属性以匹配 clipboard-event-dataitems 中的条目。

    2. 如果 e 是 "copy" 或 "cut",则

      1. 将关联的 DataTransfer 对象的内部拖放数据存储模式标志设置为读/写

  8. eclipboardData 设置为 clipboard-event-data

  9. eisTrusted 设置为 trusted

  10. ecomposed 设置为 true。

  11. target 处分派事件 e,该事件冒泡且可取消,并使用 ClipboardEvent 接口。

    事件分派期间数据访问的实现要求在[HTML]中定义。下面给出了一些额外的剪贴板事件特定处理规则:

    为什么在这里?为什么不在 HTML 规范中?

    1. 如果脚本调用 clearData()clear() 并且 DataTransfer 对象的内部拖放数据存储模式标志是读/写,则

      1. clear-was-called 标志设置为 true。如果给定了参数,则将该参数添加到 types-to-clear 列表中。

    2. 如果脚本调用 setData() 或修改项目并且 clear-was-called 标志为 true,则

      1. 如果 types-to-clear 列表为空,则

        1. clear-was-called 标志设置为 false,则

      2. 否则,如果 setData()type 参数或新项目的拖放数据项类型字符串types-to-clear 列表中找到,则

        1. 将其从列表中删除。如果列表现在为空,则将 clear-was-called 标志设置为 false。

    3. 如果脚本调用 getData() 或访问 DataTransferItemList 中的项目并且设置了 clipboard-entry,则

      1. 检查剪贴板数据的序列号是否与 clipboard-entry 匹配。如果剪贴板不再包含相同的条目,则将 DataTransferItemList 对象的内部拖放数据存储模式设置为受保护

    警告!监听粘贴事件的恶意脚本可能会设置一个无限循环,以便读取用户将来放置在剪贴板上的内容。在无法使用剪贴板序列号的平台上,应实施其他限制。

处理 HTML 粘贴事件

输入

clipboard-part,要处理的剪贴板部分

clipboard-event-data,此事件的 DataTransfer 对象

输出

  1. new-data 为一个新的 DataTransferItem, 其拖放数据项种类设置为纯 Unicode 字符串拖放数据项类型字符串相应地设置为 text/htmlapplication/xhtml+xml

  2. clipboard-part 中提取标记,并使用相关的解析器构建 DOM 树。

  3. 如果标记的源 URL 已知,则使用源 URL 作为基础 URL 解析 HREF 和 SRC 属性中的所有相对 URL,并将相应的属性设置为解析后的绝对 URL。

  4. 如果标记的来源是本地应用程序,则检查是否存在对本地文件和/或操作系统剪贴板内容的其他部分的引用。如果找到此类引用,则对子部分的引用必须使用 cid: URL 方案 [RFC2392] 替换为内容 ID 引用。为此,请按照以下步骤处理每个引用本地文件或剪贴板部分的属性:

    这些步骤是必要的吗?我们是否了解支持具有内部引用的多个部分的本机(平台)剪贴板实现?

    此功能存在风险,因为尚不清楚是否需要它,并且难以进行跨平台测试。

    1. 如果 clipboard-event-dataitems 已经包含对引用的文件或剪贴板部分的条目,则

      1. itemNumber 设置为现有条目的索引。

    2. 否则,

      1. new-file-data 为一个新的 DataTransferItem, 其拖放数据项种类设置为 "file",拖放数据项类型字符串设置为文件或剪贴板部分的 MIME 类型(如果已知),如果文件类型未知,则设置为 application/octet-stream

      2. file-info 为一个新的 File 对象,其 name 设置为 HTML 属性内容的名称部分,lastModified 设置为引用文件的时间戳,如果条目引用剪贴板部分,则设置为 0。

      3. new-file-data 的内部 File 对象设置为 file-info

      4. new-file-data 添加到 clipboard-event-dataitems 中,并令 itemNumber 为此条目在 DataTransferItemList 中的索引。

    3. 更新引用本地文件或剪贴板部分的 DOM 属性,使其包含字符串 'cid:' 后跟 itemNumber

  5. 序列化处理后的 DOM 并使用生成的 HTML 代码更新 new-data

  6. new-data 添加到 clipboard-event-dataitems 中。

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语的组合来表达。 本文档规范部分中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL” 应按照 RFC 2119 中的描述进行解释。 但是,为了便于阅读, 这些词在本规范中不大写显示。

本规范的所有文本都是规范性的, 明确标记为非规范性的章节、示例和注释除外。 [RFC2119]

本规范中的示例以“例如”一词开头, 或者通过 class="example" 与规范性文本分开, 如下所示:

这是一个信息性示例的例子。

信息性注释以“注意”一词开头, 并通过 class="note" 与规范性文本分开, 如下所示:

注意,这是一个信息性注释。

一致性算法

作为算法一部分以祈使语气表述的要求 (例如“去除任何前导空格字符” 或“返回 false 并中止这些步骤”) 应根据引入算法时使用的关键词 (“必须”、“应该”、“可以”等)的含义进行解释。

以算法或特定步骤形式表述的一致性要求 可以用任何方式实现, 只要最终结果等效即可。 特别是,本规范中定义的算法 旨在易于理解, 并非旨在追求高性能。 鼓励实现者进行优化。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性参考文献

[DOM]
Anne van Kesteren. DOM 标准. 实时标准. URL: https://dom.spec.whatwg.org/
[ENCODING]
Anne van Kesteren. 编码标准. 实时标准. URL: https://encoding.spec.whatwg.org/
[FileAPI]
Marijn Kruisselbrink. 文件 API. 2024年12月4日. WD. URL: https://www.w3.org/TR/FileAPI/
[HTML]
Anne van Kesteren; 等. HTML 标准. 实时标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 实时标准. URL: https://infra.spec.whatwg.org/
[MIMESNIFF]
Gordon P. Hemsley. MIME 嗅探标准. 实时标准. URL: https://mimesniff.spec.whatwg.org/
[PERMISSIONS]
Marcos Caceres; Mike Taylor. 权限. 2024年12月20日. WD. URL: https://www.w3.org/TR/permissions/
[RFC2119]
S. Bradner. RFC 中用于指示需求级别的关键词. 1997年3月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC2392]
E. Levinson. 内容 ID 和消息 ID 统一资源定位符. 1998年8月. 建议标准. URL: https://www.rfc-editor.org/rfc/rfc2392
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 实时标准. URL: https://webidl.spec.whatwg.org/

信息性参考文献

[HTML5]
Ian Hickson; 等. HTML5. 2018年3月27日. REC. URL: https://www.w3.org/TR/html5/
[MICROSOFT-CLIP-OP]
关于 DHTML 数据传输. 微软开发者网络.. URL: https://msdn.microsoft.com/en-us/ie/ms537658(v=vs.94)
[SVG11]
Erik Dahlström; 等. 可缩放矢量图形 (SVG) 1.1 (第二版). 2011年8月16日. REC. URL: https://www.w3.org/TR/SVG11/

IDL 索引

dictionary ClipboardEventInit : EventInit {
  DataTransfer? clipboardData = null;
};

[Exposed=Window]
interface ClipboardEvent : Event {
  constructor(DOMString type, optional ClipboardEventInit eventInitDict = {});
  readonly attribute DataTransfer? clipboardData;
};

partial interface Navigator {
  [SecureContext, SameObject] readonly attribute Clipboard clipboard;
};

typedef Promise<(DOMString or Blob)> ClipboardItemData;

[SecureContext, Exposed=Window]
interface ClipboardItem {
  constructor(record<DOMString, ClipboardItemData> items,
              optional ClipboardItemOptions options = {});

  readonly attribute PresentationStyle presentationStyle;
  readonly attribute FrozenArray<DOMString> types;

  Promise<Blob> getType(DOMString type);

  static boolean supports(DOMString type);
};

enum PresentationStyle { "unspecified", "inline", "attachment" };

dictionary ClipboardItemOptions {
  PresentationStyle presentationStyle = "unspecified";
};

typedef sequence<ClipboardItem> ClipboardItems;

[SecureContext, Exposed=Window]
interface Clipboard : EventTarget {
  Promise<ClipboardItems> read(optional ClipboardUnsanitizedFormats formats = {});
  Promise<DOMString> readText();
  Promise<undefined> write(ClipboardItems data);
  Promise<undefined> writeText(DOMString data);
};

dictionary ClipboardUnsanitizedFormats {
  sequence<DOMString> unsanitized;
};

dictionary ClipboardPermissionDescriptor : PermissionDescriptor {
  boolean allowWithoutGesture = false;
};

问题索引

Web 开发人员可能对潜在的拒绝原因感兴趣。
在作者调用 getType 后,应该可以从系统剪贴板异步读取数据,但是,这组步骤意味着数据将在读取时提供。
某些操作系统包含多个剪贴板(例如 Linux 中的“primary”、“secondary”、“selection”)。定义从哪些剪贴板读取数据。
添加已清理副本的定义。
clipboard-write 已在 https://github.com/w3c/clipboard-apis/pull/164 中移除。
data 包含多个项目并且操作系统支持多个本机剪贴板项目时,当前算法会将项目按顺序写入系统剪贴板,而不是集体写入。
添加已清理副本的定义。
clipboard-write 已在 https://github.com/w3c/clipboard-apis/pull/164 中移除。
将事情留给实现是不好的。这里应该发生什么?
“从剪贴板中删除特定类型”功能存在风险。它似乎并不那么重要,而且尚不清楚它是否可以在相关平台上轻松实现。
某些操作系统包含多个剪贴板(例如 Linux 中的“primary”、“secondary”、“selection”)。定义数据写入到哪些剪贴板。
更详细地说明读取 webCustomFormatMap 的过程。
为什么在这里?为什么不在 HTML 规范中?
这些步骤是必要的吗?我们是否了解支持具有内部引用的多个部分的本机(平台)剪贴板实现?
此功能存在风险,因为尚不清楚是否需要它,并且难以进行跨平台测试。
MDN

Clipboard/read

Firefox🔰 90+Safari13.1+Chrome?
Opera63+Edge?
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet12.0+Opera Mobile54+
MDN

Clipboard/readText

FirefoxNoneSafari13.1+Chrome66+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Clipboard/write

In all current engines.

Firefox87+Safari13.1+Chrome66+
Opera63+Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android66+Android WebView?Samsung Internet12.0+Opera Mobile54+
MDN

Clipboard/writeText

In all current engines.

Firefox63+Safari13.1+Chrome66+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Clipboard

In all current engines.

Firefox63+Safari13.1+Chrome66+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ClipboardEvent/ClipboardEvent

In all current engines.

Firefox22+Safari10.1+Chrome58+
Opera?Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ClipboardEvent/clipboardData

In all current engines.

Firefox22+Safari10.1+Chrome41+
Opera?Edge79+
Edge (Legacy)12+IE5+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ClipboardEvent

In all current engines.

Firefox22+Safari10.1+Chrome41+
Opera?Edge79+
Edge (Legacy)12+IE4+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ClipboardItem/ClipboardItem

In all current engines.

Firefox🔰 87+Safari13.1+Chrome98+
Opera?Edge98+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android98+Android WebView?Samsung Internet?Opera Mobile?
MDN

ClipboardItem/getType

In all current engines.

Firefox🔰 87+Safari13.1+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android84+Android WebView?Samsung Internet?Opera Mobile?
MDN

ClipboardItem/presentationStyle

Firefox🔰 87+Safari13.1+ChromeNone
Opera?EdgeNone
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ClipboardItem/types

In all current engines.

Firefox🔰 87+Safari13.1+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android84+Android WebView?Samsung Internet?Opera Mobile?
MDN

ClipboardItem

In all current engines.

Firefox🔰 87+Safari13.1+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android84+Android WebView?Samsung Internet?Opera Mobile?
MDN

Element/copy_event

In all current engines.

Firefox22+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari3+Chrome for Android?Android WebView?Samsung Internet?Opera Mobile12.1+
MDN

Element/cut_event

In all current engines.

Firefox22+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari3+Chrome for Android?Android WebView?Samsung Internet?Opera Mobile12.1+
MDN

Element/paste_event

In all current engines.

Firefox22+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari3+Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile12.1+
MDN

Navigator/clipboard

In all current engines.

Firefox63+Safari13.1+Chrome66+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?