前言

最近做了一个关于这方面的需求,自己也是第一次做关于这一块的内容,现将相关实现进行一个梳理。JS对粘贴板的访问有如下几种方式

  • 原生方法 execCommand
  • 原生方法 Clipboard
  • 第三方库 clipboard.js(推荐)

经调研与实践,最终选取第三方库 clipboard.js 来实现自己的需求

document.execCommand()

已废弃:此功能已过时。 尽管它可能在某些浏览器中仍然有效,但不鼓励使用它,因为它可以随时被删除。 尽量避免使用它。

这是MDN文档给出的提醒,MDN文档甚至没有给出如何具体使用。
下面简单介绍一下execCommand的用法

  1. <input type="text" id="input" value="123">
  2. <button onclick="copy()">copy</button>
  3. <script>
  4. function copy() {
  5. const inputEle = document.querySelector('#input');
  6. inputEle.select();
  7. // 必须得由用户手动调用才能触发
  8. document.execCommand('copy');
  9. // cut、delete(删除选中元素) 同理
  10. // document.execCommand('cut');
  11. }
  12. </script>

copy、cut等命令会返回一个布尔值,确定浏览器此功能是否可用。

考虑到安全原因, document.execCommand(‘paste’)操作已经被禁止了。

如果想使用 execCommand 方法,又不想页面中出现可编辑区域,可以用下述办法取巧

  1. <button onclick="copy2Clipboard('隐藏复制!!!')">copy</button>
  2. <script>
  3. function copy2Clipboard(content) {
  4. const dom = document.createElement('input');
  5. dom.value = content;
  6. document.body.appendChild(dom);
  7. dom.select();
  8. document.execCommand('copy');
  9. document.body.removeChild(dom);
  10. };
  11. </script>

经调研,execCommand命令存在以下缺陷

  1. 不够灵活,只能操作input, textarea或具有contenteditable属性的元素
  2. execCommand是同步操作,如果复制/粘贴大量数据,页面会出现卡顿。
  3. 有些浏览器还会跳出提示框,要求用户许可,这时在用户做出选择前,页面会失去响应。

    Clipboard

    剪贴板 Clipboard API 提供了响应剪贴板命令与异步读写系统剪贴板的能力。从权限 Permissions API 获取权限之后,才能访问剪贴板内容;如果用户没有授予权限,则不允许读取或更改剪贴板内容。
    该 API 被设计用来取代使用 document.execCommand() 的剪贴板访问方式。
    可用navigator.clipboard属性来检测浏览器是否支持该API,若返回undefined则不支持

    读取粘贴板

    1. <button onclick="readClip()">readClip</button>
    2. <script>
    3. function readClip() {
    4. // 读取文本
    5. navigator.clipboard.readText().then(clipText => console.log(clipText));
    6. // navigator.clipboard.read() 读取数据,比如图片
    7. }
    8. </script>
  4. Chrome 浏览器规定,只有 HTTPS 协议的页面才能使用这个 API。不过,开发环境可正常使用

  5. 与粘贴板相关的权限有两个,clipboard-write(写权限)和clipboard-read(读权限)。写权限”自动授予脚本,而“读权限”因为涉及到用户隐私,必须由用户明确同意授权。

可通过如下方式查看是否有相关读写权限

  1. navigator.permissions.query({ name: 'clipboard-write' });

写入粘贴板

  1. <button onclick="copy2clip()">copy2clip</button>
  2. <script>
  3. function readClip() {
  4. // 写入文本
  5. navigator.clipboard.writeText("写入到粘贴板").then(() => console.log("成功写入剪贴板"));
  6. // navigator.clipboard.write 写入任意数据
  7. }
  8. </script>

clipboard.js库

复制文本到剪贴板的方法,没有flash,没有框架。 压缩后只有 3kb

安装

  1. // node安装
  2. npm install clipboard --save
  3. // CDN引入
  4. <script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js"></script>

基础用法

复制/剪切 另外一个元素的文本

  1. <!-- Target 提供复制的文本 -->
  2. <input id="foo" value="https://github.com/zenorocha/clipboard.js.git">
  3. <!-- 支持复制其他元素内容 -->
  4. <!-- <div id="foo">div元素</div> -->
  5. <!-- 当存在多个target时,复制第一个 -->
  6. <!-- Trigger 复制功能的触发器,触发器可以是其他元素,能够被点击就会被触发 -->
  7. <!-- data-clipboard-target 设定target,语法同JQuerry -->
  8. <button class="btn" data-clipboard-target="#foo">copy</button>
  9. <!-- 通过设置 data-clipboard-action 属性将触发器变为剪切功能,共两个值,默认为copy -->
  10. <!-- 只有可输入元素(input、textarea等)才支持剪切 -->
  11. <button class="btn" data-clipboard-target="#foo" data-clipboard-action="cut">cut</button>
  12. <script>
  13. // 查看浏览器是否支持clipboard 返回一个布尔值,
  14. // 如果不支持,你可以隐藏复制/剪切按钮。
  15. ClipboardJS.isSupported()
  16. // 对选中的元素进行监听,语法同JQuerry
  17. var clipboard = new ClipboardJS('.btn');
  18. // 复制成功之后调用
  19. clipboard.on('success', function (e) {
  20. console.info('Action:', e.action);
  21. console.info('Text:', e.text);
  22. console.info('Trigger:', e.trigger);
  23. });
  24. // 复制失败之后调用
  25. clipboard.on('error', function (e) {
  26. console.error('Action:', e.action);
  27. console.error('Trigger:', e.trigger);
  28. });
  29. // 可以通过对这两个事件的监听为用户提供反馈
  30. </script>

复制自身属性的值

通过设置 data-clipboard-text属性使其复制自身

  1. <button class="btn" data-clipboard-text="自身属性的内容">copySelf</button>

高级用法

动态设置target

需要返回一个DOM节点

  1. <button class="btn" data-clipboard-target="#foo">copy</button>
  2. <div>1234</div>
  3. <script>
  4. var clipboard = new ClipboardJS('.btn', {
  5. // 将trigger的下一个兄弟节点作为target
  6. // 此时data-clipboard-targe属性不生效
  7. target: (trigger) => trigger.nextElementSibling
  8. });
  9. </script>

动态设置返回的文本

需要返回一个字符串

  1. <button class="btn">copy</button>
  2. <script>
  3. new ClipboardJS('.btn', {
  4. text: () => "动态文本内容"
  5. });
  6. </script>

设置容器

关于这一块自己也不是很理解有什么作用,现把官方解释翻译过来附在下面

要在 Bootstrap Modals 或任何其他更改焦点的库中使用,您需要将焦点元素设置为容器值。

  1. new ClipboardJS('.btn', {
  2. container: document.getElementById('modal')
  3. });

清理创建的对象

如果你想更精确地管理 DOM 的生命周期,可以使用destroy方法清理创建的对象

  1. clipboard.destroy();

清空剪切板内容

浏览器并没有提供可以清理剪切板的接口。如果网站在使用完剪切板内容后, 需要进行清理内容的话, 可以重新写入数据

  1. // ...
  2. input.value = ' '; // input的值必须有值, 不能是空字符串
  3. input.select();
  4. document.execCommand('copy')
  5. // 或者使用clipboard
  6. navigator.clipboard.writeText('');
  7. //
  8. new ClipboardJS('.btn', {
  9. text: () => " " // 必须有值, 不能是空字符串
  10. });

总结

document.execCommand用起来确实没那么舒服,甚至连官方都放弃它了,所以我们在日后的开发也应该尽量避免使用这个API,而尽量使用 Clipboard 这个API。
至于clipboard.js,虽然有依赖execCommandSelection,但我个人用起来是没什么问题的,还是比较推荐的。

参考

document.execCommand
Clipboard API