Skip to content
大纲

浏览器中实现剪切板复制内容的功能

  • 优先使用浏览器自带API navigator.clipboard.writeText(text)

  • 浏览器不支持 navigator.clipboard.writeText(text) 时:

    • 自建一个html元素,将要复制的值设置为元素内容
    • 设置元素的用户选择相关的CSS whiteSpace: 'pre', 'userSelect': all,将元素添加到页面上
    • 使用 window.getSelection() window.document.createRange() API来选中元素
    • 执行 window.document.execCommand('copy') 来复制页面中已选中的内容

代码实现(clipboard-copy源码):

js
/*! clipboard-copy. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/* global DOMException */

module.exports = clipboardCopy

function makeError () {
  return new DOMException('The request is not allowed', 'NotAllowedError')
}

async function copyClipboardApi (text) {
  // 可用时使用浏览器剪贴板API
  if (!navigator.clipboard) {
    throw makeError()
  }
  return navigator.clipboard.writeText(text)
}

async function copyExecCommand (text) {
  // 将要复制的文本放入 <span>
  const span = document.createElement('span')
  span.textContent = text

  // 保留连续的空格和换行符
  span.style.whiteSpace = 'pre'
  span.style.webkitUserSelect = 'auto'
  span.style.userSelect = 'all'

  // 将 <span> 添加到页面
  document.body.appendChild(span)

  // 创建一个代表用户选择的文本范围的选择对象
  const selection = window.getSelection()
  const range = window.document.createRange()
  selection.removeAllRanges()
  range.selectNode(span)
  selection.addRange(range)

  // 将文本复制到剪贴板
  let success = false
  try {
    // window.document.execCommand('copy') 表示复制页面上已选中的内容
    success = window.document.execCommand('copy')
  } finally {
    // 清除选择
    selection.removeAllRanges()
    window.document.body.removeChild(span)
  }

  if (!success) throw makeError()
}

async function clipboardCopy (text) {
  try {
    // 先使用自带API
    await copyClipboardApi(text)
  } catch (err) {
    // 再尝试创建元素
    try {
      await copyExecCommand(text)
    } catch (err2) {
      throw (err2 || err || makeError())
    }
  }
}