前端关于复制粘贴板的使用

3,977 阅读3分钟

前言

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

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

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

document.execCommand()

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

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

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

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

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

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

<button onclick="copy2Clipboard('隐藏复制!!!')">copy</button>
<script>
  function copy2Clipboard(content) {
    const dom = document.createElement('input');
    dom.value = content;
    document.body.appendChild(dom);
    dom.select();
    document.execCommand('copy');
    document.body.removeChild(dom);
  };
</script>

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

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

Clipboard

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

读取粘贴板

<button onclick="readClip()">readClip</button>
<script>
  function readClip() {
    // 读取文本
    navigator.clipboard.readText().then(clipText => console.log(clipText));
    // navigator.clipboard.read() 读取数据,比如图片
  }
</script>
  1. Chrome 浏览器规定,只有 HTTPS 协议的页面才能使用这个 API。不过,开发环境可正常使用
  2. 与粘贴板相关的权限有两个,clipboard-write(写权限)和clipboard-read(读权限)。写权限”自动授予脚本,而“读权限”因为涉及到用户隐私,必须由用户明确同意授权。

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

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

写入粘贴板

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

clipboard.js库

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

安装

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

基础用法

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

<!-- Target 提供复制的文本 -->
<input id="foo" value="https://github.com/zenorocha/clipboard.js.git">
<!-- 支持复制其他元素内容 -->
<!-- <div id="foo">div元素</div> -->
<!-- 当存在多个target时,复制第一个 -->

<!-- Trigger 复制功能的触发器,触发器可以是其他元素,能够被点击就会被触发 -->
<!-- data-clipboard-target 设定target,语法同JQuerry -->
<button class="btn" data-clipboard-target="#foo">copy</button>
<!-- 通过设置 data-clipboard-action 属性将触发器变为剪切功能,共两个值,默认为copy -->
<!-- 只有可输入元素(input、textarea等)才支持剪切 -->
<button class="btn" data-clipboard-target="#foo" data-clipboard-action="cut">cut</button>

<script>
  // 查看浏览器是否支持clipboard 返回一个布尔值,
  // 如果不支持,你可以隐藏复制/剪切按钮。
	ClipboardJS.isSupported()
  // 对选中的元素进行监听,语法同JQuerry
  var clipboard = new ClipboardJS('.btn');
  // 复制成功之后调用
  clipboard.on('success', function (e) {
    console.info('Action:', e.action);
    console.info('Text:', e.text);
    console.info('Trigger:', e.trigger);
  });
 // 复制失败之后调用
  clipboard.on('error', function (e) {
    console.error('Action:', e.action);
    console.error('Trigger:', e.trigger);
  });
  // 可以通过对这两个事件的监听为用户提供反馈
</script>

复制自身属性的值

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

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

高级用法

动态设置target

需要返回一个DOM节点

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

动态设置返回的文本

需要返回一个字符串

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

设置容器

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

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

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

清理创建的对象

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

clipboard.destroy();

清空剪切板内容

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

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

总结

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

参考

document.execCommand
Clipboard API