无 Flash 剪贴板

作为我们努力发展 Web 平台并使其可供新设备访问的一部分,我们正在努力减少 Web 对 Flash 的依赖。作为该努力的一部分,我们正在标准化并公开目前仅对 Flash 可用的有用功能,使其可供整个 Web 平台使用。

许多网站仍然使用 Flash 的原因之一是其复制和剪切剪贴板 API。Flash 公开了用于在按钮按下时以编程方式将文本复制到用户剪贴板的 API。这已用于实现一些方便的功能,例如 GitHub 的“克隆 URL”按钮。它也适用于编辑器 UI 等内容,这些 UI 想要公开用于复制到剪贴板的按钮,而不是要求用户使用键盘快捷键或上下文菜单。

不幸的是,Web API 尚未提供通过 JavaScript 将文本复制到剪贴板的功能,这就是为什么在禁用 Flash 的情况下访问 GitHub 会显示一个丑陋的灰色框,而该按钮应该位于该位置。幸运的是,我们有一个解决方案。编辑器 API 提供 document.execCommand 作为执行编辑器命令的入口点。"copy"cut" 命令以前已对网页禁用,但 Firefox 41(目前处于 Beta 版,计划于 9 月中旬发布)将使其在用户操作触发的回调中可供 JavaScript 使用。

使用 execCommand("cut"/"copy")

execCommand("cut"/"copy") API 仅在用户触发的回调(如单击)期间可用。如果您尝试在其他时间调用它,execCommand 将返回 false,这意味着该命令无法执行。运行 execCommand("cut") 将把当前选择复制到剪贴板,因此让我们来实现一个基本的复制到剪贴板按钮。
<pre>// 我们要附加事件的按钮
var button = ...;
// 包含我们想要复制的文本的输入
var input = ...;

button.addEventListener("click", function(event) {
event.preventDefault();
// 选择输入节点的内容
input.select();
// 复制到剪贴板
document.execCommand("copy");
});</pre>

该代码将在 Firefox 41 及更高版本中,在单击按钮时触发将输入中的文本复制到剪贴板。但是,您可能还想处理失败情况,可能回退到其他基于 Flash 的方法,例如 ZeroClipboard,甚至只是告诉用户他们的浏览器不支持该功能。

如果操作失败,例如由于在用户触发的回调之外调用,execCommand 方法将返回 false,但在旧版本的 Firefox 中,如果尝试使用 "cut""copy" API,我们也会抛出安全异常。因此,如果您想确保捕获所有失败,请确保将调用包含在 try-catch 块中,并将异常解释为失败。
<pre>// 我们要附加事件的按钮
var button = ...;
// 包含我们想要复制的文本的输入
var input = ...;

button.addEventListener("click", function(event) {
event.preventDefault();
input.select(); // 选择输入节点的内容
var succeeded;
try {
// 复制到剪贴板
succeeded = document.execCommand("copy");
} catch (e) {
succeeded = false;
}
if (succeeded) {
// 复制成功!
} else {
// 复制失败 :(
}
});</pre>

"cut" API 也通过相同的机制公开给网页,因此只需 s/copy/cut/,您就可以开始使用!

功能测试

编辑器 API 提供了一个方法 document.queryCommandSupported("copy"),旨在允许 API 使用者确定浏览器是否支持某个命令。不幸的是,在早于 41 的 Firefox 版本中,我们从 document.queryCommandSupported("copy") 返回 true,即使网页实际上无法执行复制操作。但是,尝试执行 document.execCommand("copy") 将抛出 SecurityException。因此,尝试在加载时复制并检查此异常可能是检测 Firefox 中对 document.execCommand("copy") 支持的最简单方法。
<pre>var supported = document.queryCommandSupported("copy");
if (supported) {
// 检查浏览器是否不是 41 之前的 Firefox
try {
document.execCommand("copy");
} catch (e) {
supported = false;
}
}
if (!supported) {
// 回退到其他方法,例如 ZeroClipboard
}</pre>

其他浏览器中的支持

Google Chrome 和 Internet Explorer 也都支持此 API。Chrome 使用与 Firefox 相同的限制(必须在用户触发的回调中运行)。Internet Explorer 允许在任何时候调用它,但它会首先提示用户一个对话框,询问他们是否允许访问剪贴板。

有关 API 和浏览器支持的更多信息,请参阅 MDN 文档,了解 document.execCommand().

关于 Nika Layzell

更多来自 Nika Layzell 的文章...


24 条评论

  1. mario

    信息很好。已加入书签!

    2015 年 9 月 1 日 08:22

  2. Serge

    很高兴听到!我太沮丧了,每个颜色选择器网站都使用 Flash 来复制 6 个字母的文本,所以上周我自己做了一个 - http://0xrgb.com
    Chrome 现在可以用了,但 FF 却不行(作为备用,我只是选择了颜色值,让用户在浏览器不支持剪贴板 API 的情况下手动按 Ctrl+C)。
    我很高兴听到新的 FF 将结束 zeroclipboard 和其他技巧的时代!

    2015 年 9 月 1 日 08:48

  3. Josh Triplett

    网站是否需要明确请求权限才能使用剪贴板?因为如果不需要,我完全预计许多网站会开始将不需要的数据塞入剪贴板。

    2015 年 9 月 1 日 10:24

    1. Nika Layzell

      Flash 已经存在很长时间了,它是一种机制,可以在用户触发的事件中将文本复制到用户的剪贴板。我们还没有看到它被滥用于将随机文本复制到用户的剪贴板。对话框会产生糟糕的用户体验,我们认为保持 Flash 风格的 UX(在用户触发的回调中允许复制而无需提示)消除了开发者不迁移的原因。

      2015 年 9 月 2 日 10:11

      1. voracity

        当我们可以基于证据做出安全决策时,难道不令人惊叹吗?

        2015 年 9 月 4 日 21:52

  4. 4esn0k

    谢谢,FF 会触发“copy”事件,即使选择为空。
    IE 不会。

    2015 年 9 月 1 日 11:24

    1. cpeterson@mozilla.com

      这里。我刚查看了 W3C 草案规范,但没有立即清楚哪个行为是正确的。我需要测试一下。

      2015 年 9 月 2 日 20:27

      1. cpeterson@mozilla.com

        应该说:“感谢你指出这里的行为差异。” :-)

        我刚刚测试了空选择,IE 和 Safari(OS X)都从 document.execCommand(‘copy’) 返回 false,并且不会修改操作系统剪贴板。MS Edge、Chrome 和 Firefox 返回 true 并且不会修改操作系统剪贴板。我确实在 Chrome 和 Firefox 之间发现了一个不一致性,我需要进一步调查。

        2015 年 9 月 2 日 21:06

  5. Dmitry Pashkevich

    那么,是否有“用户触发的事件”白名单供我们查询?例如,我很好奇“copy”命令是否也适用于 `mousemove` 或 `drag`。

    2015 年 9 月 1 日 11:34

    1. cpeterson@mozilla.com

      MDN 说,“剪贴板功能在任何能够弹出窗口的事件处理程序中默认启用(半受信任脚本)。”但我不知道哪些事件属于此类。

      https://mdn.org.cn/en-US/docs/Web/API/Document/execCommand#Browser_Compatibility

      2015 年 9 月 2 日 20:36

  6. Brett Zamir

    为什么认为用户触发的事件提供了任何额外的安全性?一个页面可以显示一个灰色遮罩并说“点击继续”,我相信这个要求将会满足……我赞成向用户提供强大的 API,但应该征得他们的同意。

    2015 年 9 月 1 日 14:07

    1. Luke

      但是,除非我理解错误,否则没有“paste” execCommand - 这当然会是一个安全问题!

      2015 年 9 月 1 日 20:29

      1. cpeterson@mozilla.com

        确实存在 execCommand (“paste”) 命令,但它只对 Firefox 扩展程序可用,而不是网页内容。

        2015 年 9 月 2 日 16:34

  7. _ck_

    我在 about:config 中设置什么才能禁用此 API,因为现在任何网站都可以在我点击页面上的任何链接时清空我的剪贴板(或将其填充)?

    2015 年 9 月 1 日 14:51

    1. Nika Layzell

      我相信将 about:config 偏好设置“dom.allow_cut_copy”设置为 false 会禁用这些 API。

      2015 年 9 月 2 日 10:15

    2. marsjaninzmarsa

      现在?甚至在 Flash 可以做到之前…

      2015 年 9 月 6 日 下午 6:09

    3. Antoine

      无论如何,你可能会被 Flash 按钮欺骗(除非你总是禁用 Flash)

      2015 年 9 月 8 日 上午 5:12

  8. Matthew Douglass

    加载时复制的例子
    a) 会失败,因为它不是在用户触发的操作期间
    b) 如果成功,会在页面加载时清除用户的剪贴板,这将非常意外

    2015 年 9 月 1 日 下午 4:20

    1. Nika Layzell

      它会失败(返回 false - 而不是抛出错误),因为它不是在用户触发的操作期间。然而,即使它成功了,它也不会清除用户的剪贴板,因为用户将拥有一个空的选择。空选择指定的默认操作是保持剪贴板不变。

      2015 年 9 月 2 日 上午 10:02

  9. Dane MacMillan

    在我那个年代,我们不得不教育用户使用 Ctrl+C 以及那些不可靠的标题文本,这些文本永远不会停留。接下来,你会发现有一个书签 API。

    (╯°□°)╯ ┻━┻

    2015 年 9 月 4 日 上午 7:39

  10. voracity

    仍然无法粘贴文本,或者更确切地说,在用户不点击任何东西的情况下复制文本 - 现在应该就是这样。

    然而!网络与原生之间唯一的真正差距就是这种许可能力。(很多人都谈论性能,但这越来越不相关 - 我猜想,这与如今大约 10% 的应用程序相关,而且这个数字正在下降。)

    在某个时刻,网络社区将不得不弄清楚如何以安全的方式*将这些功能公开给所有网页,_阻止_琐碎的用途**,以一种与原生竞争的等效方式,同时保持去中心化。最后一点尤其重要 - 通过中心化的审查与原生竞争很容易,但这根本不是网络的意义所在。(否则,我们还不如让互动电视复活!)

    这是一个艰巨的任务,但我希望网络社区能够胜任。我们有像 Uber 和 Airbnb 这样的东西,它们能够在一定程度上实现去中心化,同时仍然管理安全风险,所以我抱有希望。

    * “安全”仅仅意味着用户知道并理解网站正在做什么,并且同意(或者如果明确要求,会同意)。
    ** 通过这一点,我也意味着用户不会感到被迫给予网站访问与之无关内容的权限;用户不会被欺骗,以为需要权限而实际上不需要;用户不会仅仅出于习惯或因为“每个人都这样做”而授予权限。

    2015 年 9 月 4 日 下午 10:34

  11. zilch

    允许网站破坏/替换我的剪贴板内容?说真的?

    2015 年 9 月 7 日 上午 3:02

  12. Zeno Rocha

    如果您对此感兴趣,您可能还想查看 Clipboard.js :)

    http://zenorocha.github.io/clipboard.js/

    2015 年 9 月 27 日 下午 5:12

  13. Madis

    如何知道“点击”事件是由用户点击某物触发的,还是由脚本触发的。它们可以在 JavaScript 中识别吗,还是只在 Firefox 的后台引擎中识别?

    此外,如果我使用 Selenium 并希望复制粘贴工作(我不确定 Selenium 的确切工作原理,也许它不会通过 JS 触发点击事件)。

    2015 年 10 月 1 日 上午 6:34

本文的评论已关闭。