剪贴板 API 和事件

W3C 工作草案,

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

摘要

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

本文档状态

本节描述了本文档在发布时的状态。当前 W3C 出版物列表及本技术报告的最新修订版可在 W3C 标准与草案索引中找到。

本文档由 Web Editing 工作组 作为工作草案,采用 推荐标准流程发布。 作为工作草案发布并不代表获得 W3C 及其成员的认可。

本文档为草案文档,可能随时被更新、替换或废止。 除作为在研项目外,不适宜引用本文件。

本文件的变更可在 https://github.com/w3c/clipboard-apis 跟踪。

本文件由遵守 W3C 专利政策 的工作组制定。W3C 维护着与该组交付物相关的任何专利披露的公开列表;该页面也包含专利披露的说明。知晓某专利且认为其包含必要专利权利要求的个人,必须按照W3C 专利政策第6节披露相关信息。

本文件受 2025年8月18日 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 事件。这些更改可能由以下任何原因(非详尽列表)引起:

5.2.1.1. 触发 clipboardchange 事件

要在给定Document document触发 clipboardchange 事件

  1. 如果 document 没有粘性激活,并且 document 没有 从剪贴板读取的权限,则返回。

  2. globaldocument相关全局对象

  3. 如果 document 具有系统焦点

    1. types强制数据类型列表,这些类型可用于系统 剪贴板

    2. changeId 为在给定 document 的情况下运行生成 changeId 的结果。

    3. eventInit 为一个新的 ClipboardChangeEventInit 字典,其 types 成员设置为 types,并且其 changeId 成员设置为 changeId

    4. global触发一个事件,其名称为 clipboardchange, 使用 ClipboardChangeEvent, 并带有 eventInit

  4. 如果 document 没有系统焦点

    1. documentclipboardchange 待处理标志设置为 true。

用户代理可以选择跳过对在事件发送前已被更新为更新版本的剪贴板内容的clipboardchange事件的触发。这种优化可以提升在剪贴板更改频繁发生的场景下的性能,因为传递过时的更改通知对网页应用没有价值,反而会占用处理资源。

5.2.1.2. 文档聚焦步骤

Document document获得系统焦点时:

  1. 如果 documentclipboardchange 待处理标志为 true:

    1. documentclipboardchange 待处理标志 设置为 false。

    2. types强制数据类型列表,这些类型可用于系统 剪贴板

    3. changeId 为在给定 document 的情况下运行生成 changeId的结果。

    4. eventInit 为一个新的 ClipboardChangeEventInit 字典,其 types 成员设置为 types,并且其 changeId 成员设置为 changeId

    5. globaldocument相关全局对象

    6. 触发一个事件,其名称为 clipboardchange, 目标为 global,使用 ClipboardChangeEvent, 并带有 eventInit

对于嵌套浏览上下文中的文档,clipboardchange事件将在每个Document中根据其自身的焦点状态独立触发。一次剪贴板更改将在具有系统焦点的单一文档中触发(如果该文档有粘性激活或持久剪贴板权限)。

注意:只有在粘性激活后,clipboardchange事件才可用,除非文档拥有从剪贴板读取的持久权限。在支持持久剪贴板权限的用户代理中,拥有该权限的站点可在无粘性激活的情况下收到clipboardchange事件,因为该权限已经授予访问更敏感剪贴板数据的权限。

changeId为每次剪贴板更改操作提供一个唯一标识符。对于相同剪贴板内容更改,所有具有相同存储键的窗口和标签页会收到具有相同changeId的事件,使多窗口应用可以去重事件避免重复处理。该标识符是存储键相关的,并不具备跨存储键的关联能力。

clipboardchange事件不会冒泡也不可取消,因为它不是由用户操作而是由于系统剪贴板状态的更改触发的。

dictionary ClipboardChangeEventInit : EventInit {
  sequence<DOMString> types = [];
  bigint changeId = 0;
};
types

一个由 DOMString 组成的序列,表示强制数据类型,这些类型可用于系统 剪贴板

changeId

一个 bigint ,表示剪贴板更改操作的唯一标识符。

[Exposed=Window]
interface ClipboardChangeEvent : Event {
  constructor(DOMString type, optional ClipboardChangeEventInit eventInitDict = {});
  readonly attribute FrozenArray<DOMString> types;
  readonly attribute bigint changeId;
};
types

返回一个由 FrozenArrayDOMString 对象组成的数组,指示事件被触发时强制数据类型系统剪贴板上可用。可选 数据类型和 自定义格式会被排除,以限制指纹识别面。

changeId

返回一个 bigint ,表示此次特定剪贴板更改操作的唯一标识符。 对于同一次剪贴板更改,此标识符在具有相同存储 键的所有窗口和标签页中保持一致, 使应用能够在多个窗口收到同一个剪贴板 更改通知时对事件进行去重。

changeId 是一个通过加密方式派生的 128 位整数。唯一保证是在有内容 写入剪贴板之后,changeId 将产生一个不同于写入操作之前的值。

5.2.1.3. ClipboardChangeEvent 构造步骤

ClipboardChangeEvent(type, eventInitDict) 的构造步骤如下:

  1. this.types设为eventInitDict["types"]的克隆

  2. this.changeId设为eventInitDict["changeId"]。

5.2.1.4. ChangeId 生成

要为一个 Document document 生成 changeId

  1. globalChangeId 为一个用户代理特定的唯一标识符,表示系统剪贴板的当前 状态。每当系统 剪贴板被修改时,此标识符都会改变,并且会在用户代理重启时重置。

  2. storageKey 为在给定 document为非存储用途获取 存储键相关设置对象的情况下运行结果。

  3. storageKeyBytesstorageKey 的某种用户代理特定的二进制表示。

  4. hashedValue 为将加密哈希函数(例如 SHA-256)应用于 globalChangeId(作为字节)和 storageKeyBytes 的拼接结果所得的结果。

  5. 返回一个从 hashedValue 派生出的 128 位整数(例如,通过取哈希输出的前 128 位)。

上述算法确保来自同一源且具有相同 分区的文档,会针对同一次剪贴板修改接收相同的变更 ID,从而能够在多个窗口和标签页之间正确地对事件 去重,同时防止可用于跟踪的跨分区关联。随着客户端存储分区的变更被纳入存储键 定义,此方法将自动在各分区之间提供匿名化。

changeId 不会在浏览器重启后持久存在,因为 globalChangeId 计数器会在用户 代理重启时重置。类似地,当用户清除站点数据时,受影响的标签页应该被刷新,这会导致 事件监听器被重新附加,并且只接收带有新变更 ID 的未来事件。

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

clipboardchange 事件使 Web 应用能够高效地监控 剪贴板变化,并根据可用的数据格式提供动态用户界面:
// 对于具有多个窗口的应用,跟踪已处理的变更 ID 以避免重复
const processedChangeIds = new Set();

// 监听剪贴板变化
navigator.clipboard.addEventListener('clipboardchange', (e) => {
  // 使用 changeId 对多个窗口之间的事件去重
  if (processedChangeIds.has(e.changeId)) {
    return; // 此变更已经被处理过
  }
  processedChangeIds.add(e.changeId);

  // 检查剪贴板上有哪些可用的数据类型
  const hasText = e.types.includes('text/plain');
  const hasHTML = e.types.includes('text/html');
  const hasImage = e.types.includes('image/png');

  // 根据可用格式更新 UI
  document.getElementById('paste-text-btn').disabled = !hasText;
  document.getElementById('paste-html-btn').disabled = !hasHTML;
  document.getElementById('paste-image-btn').disabled = !hasImage;

  // 对于远程桌面应用,每次变更只将剪贴板同步到远程一次
  if (hasText || hasHTML || hasImage) {
    syncClipboardToRemote(e.changeId);
  }
});

// 或者,也可以使用 onclipboardchange 属性
// navigator.clipboard.onclipboardchange = (e) => { ... };

这种事件驱动方法比使用 read()readText() 等方法轮询剪贴板更高效, 并且可在要求用户激活才能访问剪贴板的浏览器中工作,因为 UI 可以立即响应剪贴板变化,而无需等待计时器 触发。 changeId 对于具有多个窗口的应用尤其有用, 可确保在具有相同存储键的所有窗口中,每次剪贴板变更只被处理一次。

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 对象具有关联的 types 数组,它是一个 FrozenArray<DOMString>。

一个 ClipboardItem 对象具有关联的 读取时的剪贴板变更计数, 它初始为 null。

一个 ClipboardItem 对象具有关联的 源系统剪贴板 项,它是一个系统剪贴板项或 null,初始为 null。

一个 ClipboardItem 对象具有关联的 未清理的 MIME 类型,它是一个sequence<DOMString>, 初始为空。

一个 ClipboardItem 对象具有关联的 带解析器的表示, 它是一个从字符串(传递给 getType()MIME 类型, 包括存在时的 `"web "` 前缀)到 Promise<Blob> 的映射, 初始为空。每个条目表示针对该类型的一次 OS 剪贴板读取,该读取已经完成或 当前正在进行。

注: 此映射确保对从 read() 获得的 ClipboardItem 上同一 MIME 类型的并发 getType() 调用共享一次 OS 剪贴板读取。第一次调用会把一个待处理的 Promise 插入到映射中并发起读取;随后对同一 MIME 类型的调用返回现有的 Promise, 而不会重新读取系统剪贴板

当一个 ClipboardItemread() 创建时,它充当惰性获取器,而不是数据快照。它的types 数组反映 read() 调用时系统剪贴板上可用的格式, 但实际载荷字节要到 getType() 被调用时才会读取。如果在 read() 调用和后续 getType() 调用之间,系统 剪贴板内容发生变化,则该 getType() 调用将被拒绝。直接通过 ClipboardItem(items, options) 构造函数构造的 ClipboardItem 不受此行为约束。

要在给定一个剪贴板项 clipboardItem 和一个 Realm realm 的情况下,创建一个 ClipboardItem 对象,运行以下步骤:

  1. clipboardItemObject 为一个带有 realm新的 ClipboardItem

  2. clipboardItemObject剪贴板项设置为 clipboardItem

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

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

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

  3. this剪贴板项设置为一个新的剪贴板项

  4. this剪贴板项呈现样式设置为 options["presentationStyle"]。

  5. types 为一个 DOMString 列表。

  6. 对于 items 中的每个(keyvalue):

    1. representation 为一个新的表示

    2. isCustomfalse

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

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

      2. isCustom 设置为 true

    4. representationisCustom 标志设置为 isCustom

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

    6. 如果 mimeType 为 failure,则抛出一个 TypeError

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

    上述步骤防止用户代理已知的 mime-types 与作者意图作为 自定义类型处理的 mime-types 之间发生冲突。例如,作者的 items 列表可能同时包含 "text/html" 和 "web text/html" 的表示。

    1. representationMIME 类型设置为 mimeType

    2. representation数据设置为 value

    3. representation 追加到 this剪贴板项表示 列表

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

    5. 如果 isCustomtrue,则为 mimeTypeString 加上 `"web "` 前缀。

    6. mimeTypeString 添加到 types

  7. thistypes 数组设置为从 types 运行创建冻结数组所得的结果。

7.2.1. presentationStyle

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

7.2.2. types

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

7.2.3. getType(type)

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

  1. realmthis相关 Realm

  2. isCustomfalse

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

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

    2. isCustom 设置为 true

  4. mimeType 为在给定 type 的情况下解析 MIME 类型所得的结果。

  5. 如果 mimeType 为 failure,则抛出一个 TypeError

  6. itemTypeListthis剪贴板项表示 列表

  7. prealm 中的一个新的 promise

  8. 对于 itemTypeList 中的每个 representation

    1. 如果 representationMIME typemimeType,并且 representationisCustomisCustom,则:

      1. 如果 this读取时的剪贴板变更 计数不是 null,并且当前剪贴板 变更计数不等于 this读取时的剪贴板变更 计数,则在 realm 中用一个 "InvalidStateError" DOMException 拒绝 p,并返回 p

        注: 这确保了永远不会返回过期 数据。如果系统剪贴板内容自 read() 被调用以来已发生变化,则这必须失败,而不是返回与当前系统剪贴板状态不对应的数据。

        注: null 的读取时的剪贴板变更 计数表示此 ClipboardItem 是由作者直接构造的(例如,通过 ClipboardItem(items, options)), 而不是从 read() 获得的。 在这种情况下,不需要过期数据检查,因为该数据并非源自 系统剪贴板

      2. 如果 this读取时的剪贴板变更 计数不是 null,则:

        注: 此分支涵盖从 ClipboardItems 获得的 read(), 对于这些项,OS 剪贴板读取会推迟到此时。为确保每种类型的读取 最多只发生一次——即使针对同一 MIME 类型并发多次调用 getType()——生成的 Promise 会缓存在 this带解析器的 表示映射中,并以一个规范化类型字符串作为键,使 `"text/html"` 和 `"web text/html"` 被独立跟踪,同时同一类型的不同大小写写法(例如 `"text/HTML"` 和 `"text/html"`)会折叠为单个条目。

        1. keymimeTypeessence。如果 isCustom 为 true,则为 key 加上 `"web "` 前缀。

        2. 如果 this带解析器的 表示[key] 存在,则返回 this带解析器的 表示[key]。

        3. 设置 this带解析器的 表示[key] 为 p

        4. 并行运行以下步骤:

          1. clipboardItemthis源 系统剪贴板项

          2. 如果 clipboardItem 为 null,则在剪贴板任务源排队一个全局任务, 给定 realm全局对象,以在 realm 中用一个 "InvalidStateError" DOMException 拒绝 p,然后中止这些步骤。

          3. 如果 isCustom 为 true,则:

            1. mapNameOS 特定 自定义映射名称

            2. mapRepresentationclipboardItem系统 剪贴板表示列表中,其名称mapName系统 剪贴板表示。如果不存在这样的系统 剪贴板表示,则在剪贴板任务 源排队一个全局 任务,给定 realm全局对象,以在 realm 中用一个 "NotFoundError" DOMException 拒绝 p,然后中止这些步骤。

            3. webCustomFormatMapString 为从 mapRepresentation数据 反序列化得到的 JSON 字符串。

            4. osFormatNamewebCustomFormatMapString 中键与 mimeType 序列化后匹配的值。

            5. 如果没有找到 osFormatName,则在剪贴板任务 源排队一个全局 任务,给定 realm全局对象,以在 realm 中用一个 "NotFoundError" DOMException 拒绝 p,然后中止这些步骤。

          4. 否则,令 osFormatName 为在给定 mimeType 的情况下运行OS 特定 知名格式所得的结果。

          5. clipboardRepresentationclipboardItem系统剪贴板 表示列表中,其名称osFormatName系统剪贴板 表示。如果不存在这样的系统剪贴板 表示,则在剪贴板任务源排队一个全局任务, 给定 realm全局对象,以在 realm 中用一个 "NotFoundError" DOMException 拒绝 p,然后中止这些步骤。

          6. rawDataclipboardRepresentation数据

          7. cleanDatarawData 的一个副本。

          8. 如果 mimeTypeessence 位于 this未清理 MIME 类型中,并且 mimeTypeessence 位于可选 未清理数据类型列表中,则什么也不做。

          9. 否则,如果 mimeTypeessence 不是 "image/png", 用户代理可以清理 cleanData

          10. blob 为一个 Blob, 其 typemimeType 序列化后的结果,且其 底层字节序列为 cleanData

          11. 剪贴板任务源排队一个全局任务, 给定 realm全局对象,以用 blob 兑现 p

        注: 一旦 p 已经 敲定,它会保留在 this带解析器的 表示映射中。随后对同一 MIME 类型的 getType() 调用将返回缓存的已敲定 Promise, 而不会重新读取系统剪贴板。不过,上面的过期数据检查 仍适用于每一次调用:如果系统剪贴板read() 被调用以来已经发生变化,则此 ClipboardItem 上的所有 getType() 调用都将以 "InvalidStateError" 被拒绝——即使对于先前缓存的数据也是如此。

        1. 返回 p

      3. representationDataPromiserepresentation数据

      4. 响应 representationDataPromise

        1. 如果 representationDataPromise 以值 v 兑现,则:

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

            1. dataAsBytes 为对 v 进行UTF-8 编码所得的结果。

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

            3. blobData 兑现 p

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

            1. v 兑现 p

        2. 如果 representationDataPromise 被拒绝,则:

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

            Web 开发者可能会对底层拒绝原因感兴趣。

      5. 返回 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;
};

Clipboard 接口的某些方法会接受或返回多个 ClipboardItem 对象。然而,并非所有平台都支持多个剪贴板项;在这类平台上,下面的算法会忽略 传给 write() 的第一个之外的任何 ClipboardItem 对象,并且 read()readText() 只会从 OS 获取一个剪贴板项。

剪贴板项 对象是一个由剪贴板项组成的 sequence

Web 作者需要创建一个 data,它是一个由 ClipboardItems 组成的数组,以便使用 write(data) 方法向系统剪贴板写入内容。 read() 会返回一个指向剪贴板项对象的 Promise, 该对象表示系统剪贴板数据的内容。

unsanitized 是一个由 DOMStrings 组成的 sequence, 对应于作者希望被视为可选未清理数据类型mime type

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

剪贴板任务 源会响应系统剪贴板数据的读取或写入而被触发。

7.3.1. read(formats)

read(formats) 方法必须运行以下步骤:
  1. realmthis相关 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. snapshotChangeCount 为当前剪贴板 变更计数

      注: 此时只枚举来自 data名称(格式 标识符)。每个表示的底层 载荷字节要到 getType() 被调用时才会读取。

    5. items 为一个由有序映射组成的 sequence,每个条目都具有键 "item"(一个剪贴板项)和 "originating"(一个系统剪贴板项或 null)。

    6. 对于 data 中的每个 systemClipboardItem

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

      2. 对于 systemClipboardItem 中的每个 systemClipboardRepresentation

        1. mimeType 为在给定 systemClipboardRepresentation名称的情况下, 运行从 OS 特定格式得到知名 mime type算法所得的结果。

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

        3. representation 为一个新的表示

        4. representationMIME 类型设置为 mimeType

        5. representation数据设置为 realm 中的一个新的 promise

          注:表示的 OS 剪贴板数据不会被获取,直到作者在所得的 ClipboardItem 对象上调用 getType()

        6. representation 追加到 item表示 列表

      3. 如果 item表示列表大小 大于 0,则将有序映射 «[ "item" → item, "originating" → systemClipboardItem ]» 追加到 items

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

      1. firstItemitems[0]["item"]

      2. 在给定 firstItem 的情况下运行读取 Web 自定义格式算法。

    8. 否则:

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

      2. 在给定 customItem 的情况下运行读取 Web 自定义格式 算法。

      3. 如果 customItem表示列表大小 大于 0,则将有序映射 «[ "item" → customItem, "originating" → null ]» 追加到 items

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

      1. clipboardItems 为一个 sequence<ClipboardItem>。

      2. 对于 items 的每个有序映射 entry

        1. clipboardItem 为在给定 entry["item"] 和 realm 的情况下,运行创建 ClipboardItem 对象步骤所得的结果。

        2. clipboardItem读取时的剪贴板 变更计数设置为 snapshotChangeCount

        3. clipboardItem源 系统剪贴板项设置为 entry["originating"]。

        4. 如果 formats 不为空,则将 clipboardItem未清理 MIME 类型设置为 formats["unsanitized"]。

        5. clipboardItem 追加到 clipboardItems

      3. clipboardItems 兑现 p

  5. 返回 p

// clipboard.read() 仅返回带有类型元数据的 ClipboardItem。
// 此时不会读取任何 OS 剪贴板数据。
const items = await navigator.clipboard.read();

// OS 剪贴板读取会在这里惰性发生,即调用 getType() 时。
const textBlob = await items[0].getType("text/plain");
const text = await (new Response(textBlob)).text();

7.3.2. readText()

readText() 方法必须执行以下步骤:
  1. realmthis相关 Realm

  2. prealm 中的一个新的 promise

  3. 并行运行以下步骤:

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

    2. 如果 r 为 false,则:

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

      2. 中止这些步骤。

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

      某些 OS 包含多个剪贴板(例如 Linux 的 "primary"、"secondary"、 "selection")。定义要从其中哪个读取数据。

      添加清理后副本的定义。

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

      1. 对于 data 中的每个 systemClipboardItem

        1. 对于 systemClipboardItem 中的每个 systemClipboardRepresentation

          1. mimeType 为在给定 systemClipboardRepresentation名称的情况下, 运行从 OS 特定格式得到知名 mime type算法所得的结果。

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

          3. representation 为一个新的表示

          4. 如果 representationMIME type essence是 "text/plain",则:

            1. representationMIME type设置为 mimeType

            2. representationDataPromiserepresentation数据

            3. 响应 representationDataPromise

              1. 如果 representationDataPromise 以值 v 兑现,则:

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

                  1. v 兑现 p

                  2. 返回 p

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

                  1. string 为对 v 的底层 字节序列进行UTF-8 解码所得的结果。

                  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. realmthis相关 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 为空的 sequence<Blob>。

      2. dataList 为一个 sequence<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. dataAsBytes 为对 v 进行UTF-8 编码所得的结果。

                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. realmthis相关 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 为一个空的 sequence<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. 如果script-triggered 标志已设置,则

    1. 如果script-may-access-clipboard 标志未设置,则

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

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

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

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

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

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

    1. 调用写内容到剪贴板算法,传入 DataTransferItemList 列表 itemsclear-was-called 标志 和 types-to-clear 列表。

  5. 从复制操作返回 true

8.2. 剪切操作

剪切操作包括以下步骤:

  1. 如果 script-triggered 标志已设置,则

    1. 如果 script-may-access-clipboard 标志未设置,则

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

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

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

    1. 如果在一个 可编辑上下文 中存在选择区域且允许剪切,则

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

      2. 从文档中移除选择的内容,并收起选区。

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

      4. 排队任务以触发应因该修改而触发的任何事件,详情见 § 5.3 与其他脚本和事件的集成

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

      1. 返回 false

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

    1. 调用 写内容到剪贴板 算法, 传递 DataTransferItemList 列表 itemsclear-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 ,如果相关全局对象this 具有瞬时激活;否则为 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 列表中的类型

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

将 blobs 和 option 写入剪贴板

输入

items,一个 sequence<Blob>

presentationStyle,一个剪贴板项呈现样式

输出

  1. webCustomFormats 为一个 sequence<Blob>。

  2. 对于 items 中的每个 item

    1. formatString 为在给定 itemtype 的情况下,运行OS 特定知名格式所得的结果。

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

      1. webCustomFormatStringitemtype

      2. webCustomFormat 为一个空的 type

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

      4. webMimeType 为在给定 webMimeTypeString 的情况下解析 MIME 类型所得的结果。

      5. 如果 webMimeType 为 failure,则中止所有步骤。

      6. webCustomFormattypeessence 等于 webMimeType

      7. itemtype 设置为 webCustomFormat

      8. webCustomFormat 追加到 webCustomFormats

    3. payload 为对 item 的底层字节 序列进行 UTF-8 解码所得的结果。

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

    某些 OS 包含多个剪贴板(例如 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. 如果 mimeTypeessence 是 "text/plain",则

    在 Windows 上,遵循如下所述的约定:

    1. 将 CF_UNICODETEXT 赋给 wellKnownFormat

    在 MacOS 上,遵循如下所述的约定:

    1. 将 NSPasteboardTypeString 赋给 wellKnownFormat

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

    1. 将 "text/plain" 赋给 wellKnownFormat

  3. 否则,如果 mimeTypeessence 是 "text/html",则

    在 Windows 上,遵循如下所述的约定:

    1. 将 CF_HTML 赋给 wellKnownFormat

    在 MacOS 上,遵循如下所述的约定:

    1. 将 NSPasteboardTypeHTML 赋给 wellKnownFormat

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

    1. 将 "text/html" 赋给 wellKnownFormat

  4. 否则,如果 mimeTypeessence 是 "image/png",则

    在 Windows 上,遵循如下所述的约定:

    1. 将 "PNG" 赋给 wellKnownFormat

    在 MacOS 上,遵循如下所述的约定:

    1. 将 NSPasteboardTypePNG 赋给 wellKnownFormat

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

    1. 将 "image/png" 赋给 wellKnownFormat

  5. 否则,如果 mimeTypeessence 是 "image/svg+xml",则

    在 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. webCustomFormatMapOS 特定 自定义映射名称

  2. 系统剪贴板读取 webCustomFormatMap

    更详细地指定 读取 webCustomFormatMap 的过程。

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

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

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

  5. 对于 webCustomFormatMapString 中的每个(keyvalue):

    1. mimeType 为在给定 key 的情况下解析 MIME 类型所得的结果。

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

    3. representation 为一个新的表示

    4. representationMIME 类型设置为 mimeType

    5. representationisCustom 标志设置为 true

    6. representation数据设置为一个 新的 promise

      注: 此 Web 自定义格式的 OS 剪贴板数据不会被获取,直到作者在所得的 getType() 对象上调用 ClipboardItem 为止。

    7. representation 追加到 item表示 列表

写入 Web 自定义格式

输入

items,一个 sequence<Blob>

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

  2. webCustomFormatMapOS 特定 自定义映射名称

  3. webCustomFormatMapString 为空 JSON 字符串。

  4. 对于 items 中的每个 item

    1. webCustomFormatOS 特定 自定义名称

    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。File API。2026 年 6 月 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。Permissions。2025 年 10 月 6 日。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。Content-ID 和 Message-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;
};

dictionary ClipboardChangeEventInit : EventInit {
  sequence<DOMString> types = [];
  bigint changeId = 0;
};

[Exposed=Window]
interface ClipboardChangeEvent : Event {
  constructor(DOMString type, optional ClipboardChangeEventInit eventInitDict = {});
  readonly attribute FrozenArray<DOMString> types;
  readonly attribute bigint changeId;
};

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 开发人员可能对潜在的拒绝原因感兴趣。
某些操作系统包含多个剪贴板(例如 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?