document.execCommand 已被废弃,现在我们如何与剪贴板交互?


“复制到剪贴板”是一个极为常见的web功能。多年来,我们一直依赖一个略显“古老”的 API—— document.execCommand('copy') 。它曾是我们的得力助手,但现在,它已经被正式标记为 ** 废弃(Deprecated)
** 。

document.execCommand 为何被时代抛弃?

在拥抱新事物之前,我们有必要了解旧事物的缺陷。 execCommand 主要有三大“原罪”:

  1. ** 同步执行 ** : execCommand 是一个同步操作。这意味着在执行时,它会阻塞浏览器的主线程。如果处理的数据量很大或页面复杂,可能会导致页面瞬间卡顿,影响用户体验。

  2. ** 依赖 DOM ** : execCommand 只能操作当前文档中被选中(selected)的内容。为了复制一段任意文本,我们不得不采取一些非常“黑客”的手段:

    • 动态创建一个隐藏的 <textarea><input> 元素。
    • 将想要复制的文本放入这个元素。
    • 用 JavaScript 选中该元素的全部内容。
    • 调用 document.execCommand('copy')
    • 最后,移除这个临时创建的元素。
      这一套流程繁琐、不直观,且容易出错。
  3. ** 权限模型不清晰 ** :它对剪贴板的访问权限控制非常模糊,不同浏览器的实现和限制也存在差异,这带来了一定的安全隐患。

正是因为这些原因,W3C 决定将其废弃,并推出了一个为现代 Web 量身定做的解决方案。

新的主角:强大的 Clipboard API ( navigator.clipboard )

Clipboard API 是一个异步的、基于 Promise 的现代接口,它彻底改变了我们与剪贴板交互的方式。

** 它的核心优势在于: **

  • ** 异步操作 ** :所有操作都返回 Promise,不会阻塞主线程,对性能友好。
  • ** 安全可靠 ** :它整合了浏览器的权限系统(Permissions API)。在读取剪贴板内容时,需要明确获得用户的授权,并且大多数操作要求页面在安全上下文(HTTPS)下运行。
  • ** 不依赖 DOM ** :你可以直接将字符串、图片等数据写入剪贴板,无需任何 DOM 元素作为中介。
  • ** 功能更强大 ** :除了纯文本,它还支持写入和读取更丰富的数据类型,例如图片。

实战演练:如何使用 Clipboard API

让我们来看几个最常见的场景。

场景一:复制文本到剪贴板

这是最基础的需求。使用 navigator.clipboard.writeText() ,一切都变得异常简单。

** HTML: **

<input id="copy-input" type="text" value="这是要被复制的文本">  
<button id="copy-btn">复制文本</button>  

** JavaScript: **

看,代码干净利落!我们不再需要任何隐藏的 <textarea>async/await try...catch
的组合完美地处理了异步流程和可能出现的错误(例如用户拒绝授权)。

场景二:从剪贴板读取文本

读取操作比写入更敏感,因此浏览器会向用户请求权限。 ** 注意: ** 出于安全考虑, readText() read()
方法通常只能在用户主动交互(如点击事件)的回调中调用。

** HTML: **

<button id="paste-btn">粘贴内容</button>  
<div id="paste-area" style="border: 1px solid #ccc; padding: 10px; min-height: 50px;"></div>  

** JavaScript: **

场景三:更进一步,复制图片

这是 execCommand 无法直接做到的。Clipboard API 通过 write() 方法和 ClipboardItem 对象,让复制非文本数据成为可能。

async function copyImageToClipboard(imageUrl) {  
 try {  
    // 1. 获取图片数据  
    const response = await fetch(imageUrl);  
    const blob = await response.blob(); // 将图片转换为 Blob 对象  
  
    // 2. 创建一个 ClipboardItem  
    const item = new ClipboardItem({  
      [blob.type]: blob  
    });  
  
    // 3. 写入剪贴板  
    await navigator.clipboard.write([item]);  
    console.log('图片已复制到剪贴板');  
  } catch (err) {  
    console.error('复制图片失败: ', err);  
  }  
}  
  
// 使用示例  
// copyImageToClipboard('path/to/your/image.png');  

截至目前,所有主流现代浏览器(Chrome, Firefox, Edge, Safari)都已支持 Clipboard API 的核心功能。