mishe / blog

前端碰上的问题或体会
230 stars 39 forks source link

不依赖Flash,实现剪贴板复制(转) #143

Open mishe opened 8 years ago

mishe commented 8 years ago

不依赖Flash,实现剪贴板复制

本文转载自:众成翻译 译者:奈末 链接:http://www.zcfy.cc/article/806 原文:https://hacks.mozilla.org/2015/09/flash-free-clipboard-for-the-web/

    推动Web平台进步,促使Web支持更多新设备的努力尝试从未停止,其中一项便是减少Web对Flash的依赖。作为这项工作的一部分,我们正在为全Web平台标准化并实现一些有效的特性,虽然当前这些特性只能依赖Flash。

    很多站点仍未抛弃Flash的原因之一,是复制和粘贴这两个剪贴板API。Flash提供一个API,能够在点击按钮时动态复制文本到用户的剪贴板。它备用来实现一些便利的功能,比如说GitHub的“copy to clipboard”(复制到剪贴板)按钮。同时,在开发类似文本编辑器UI的场景里它也很有价值:与其让用户使用键盘快捷键或者右键菜单,不如一键复制来得好。

    但是,Web APIs尚未提供通过JavaScript复制文本到剪贴板的功能。这也是为什么禁用Flash访问GitHub时,一个灰色丑陋的区块取代了原本的复制按钮。令人庆幸的是,我们已经有了一个办法。HTML Editing APIs提供了document.execCommand作为执行一些文本编辑命令的入口。之前网页环境下禁用了复制copy和剪切cut两个名令,但是从Firefox 41开始,用户触发的回调JavaScript已经可以使用这两个命令了。


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


    execCommand("cut"/"copy") API只能在用户触发的回调里使用,比如说一次click事件。如果在其他环境下尝试调用,execCommand将会返回false,表征该命令执行失败。运行execCommand("copy")会将当前选中的内容复制到剪贴板, 现在我们来实现一个基本的一键复制按钮。

// 事件依附的按钮
var button = ...;
// 包含待复制内容的input
var input = ...;

button.addEventListener("click", function(event) {
  event.preventDefault();
  // 选取input元素的内容
  input.select();
  // 将选区内容复制到剪贴板
  document.execCommand("copy");
});

    在Firefox 41及更高版本浏览器中,以上代码会在按钮点击后触发一次复制行为,将input内的文本复制到系统的剪贴板。不过,很可能你需要考虑不兼容的情况:可以使用另一个基于Flash的方法作为备用,例如ZeroClipboard,或者干脆告诉用户他们的浏览器不支持此功能。

    execCommand方法执行失败时会返回false,比如说在用户触发的回调之外尝试调用的时候。但是,在更早版本的Firefox中尝试对cutcopy调用,浏览器会抛出安全性异常SecurityException。所以为了确保捕获所有的异常,要将调用语句包在try-catch里,这样catch到的异常也作为调用失败处理。

// 事件依附的按钮
var button = ...;
// 包含待复制内容的input
var input = ...;

button.addEventListener("click", function(event) {
  event.preventDefault();
  input.select(); // 选取input元素的内容
  var succeeded;
  try {
    // 将选区内容复制到剪贴板
    succeeded = document.execCommand("copy");
  } catch (e) {
    succeeded = false;
  }
  if (succeeded) {
    // 复制成功
  } else {
    // 复制失败 :(
  }
});

cut API的应用同上,把copy替换为cut即可。


特性测试


    HTML Editing APIs提供了document.queryCommandSupported("copy")方法,方便使用者检测某个命令是否被浏览器支持。但是在低于Firefox 41的火狐浏览器里, 纵使实际上开发者无法使用copy命令(尝试调用document.execCommand("copy") 会得到一个SecurityException),此检测方法仍然返回了true。所以在Firefox里最简单的支持document.execCommand("copy")特性检测的办法很可能是这样:页面加载完成则尝试使用copy,检测是否抛出SecurityException

var supported = document.queryCommandSupported("copy");
if (supported) {
  // 检测浏览器是否为比Firefox 41更低的版本
  try {
    document.execCommand("copy");
  } catch (e) {
    supported = false;
  }
}
if (!supported) {
  // 使用备用方法,比如ZeroClipboard,http://zeroclipboard.org/
}


其他浏览器的兼容情况


    谷歌Chrome和IE都支持此API。Chrome和Firefox使用相同的限制策略(调用必须在用户触发的事件回调里)。IE则允许随意调用,只在第一次调用时询问用户是否允许操控剪贴板。

更多关于此API的信息或浏览器支持情况,可以查看:

MDN documentation for document.execCommand().

译者附: Can I use execcommand


关于作者


Michael Layzell

https://github.com/mystor

More articles by Michael Layzell…

mishe commented 8 years ago

测试发现pc端可以使用,但手机端无效

KevinHu-1024 commented 7 years ago

貌似当文本域是display: none时,即使里面有内容,复制出来也是空的。