Skip to content

复制内容到剪切板

功能预览

代码实现

函数调用方式及入参

具体实现代码已经封装成工具函数,直接调用即可,查看完整代码。第一个参数是要复制的文字,第二个是复制成功后的回调函数;

js
import { copyText } from '@/utils/copyText.js'
copyText(text, () => {
    ElMessage({
        type: 'success',
        message: '复制成功!'
    })
})

默认使用 navigator.clipboard.writeText(text) 实现,此方法为异步函数;但是这个API有兼容问题且限制在 https 环境下生效。

js
navigator.clipboard.writeText(text)
  .then(() => {})
  .catch((e) => {});

document.execCommand

如果默认方法调用失败,则使用 document.execCommand("copy") 兜底。原理是创建一个 input/textarea 元素,将要复制的内容赋值给它,再将其设置为 select 状态,调用 document.execCommand("copy") 完成复制。

js
function copyToClipboard(text) {
   var tempInput = document.createElement("input");
   document.body.appendChild(tempInput);
   tempInput.value = text;
   tempInput.select();
   document.execCommand("copy");
   document.body.removeChild(tempInput);
}

完整代码

js
/**
 * @description 复制文字内容到剪切板,更多内容参见:https://www.zhangxinxu.com/wordpress/?p=10150
 * @author zhangxinxu(.com)
 * @created 2021-10-22
 * @edited 2023-09-13 tips method export to outside
 */

export function copyText(button, content, success) {
  if (!button) {
    return
  }

  if (typeof content == 'function') {
    success = content
    content = null
  }

  success = success || function () {}

  // 是否降级使用
  var isFallback = !navigator.clipboard

  if (typeof button == 'string' && !content) {
    if (content === false) {
      isFallback = true
    }
    content = button
    button = null
  }

  var eleTextarea = document.querySelector('#tempTextarea')
  if (!eleTextarea && isFallback) {
    eleTextarea = document.createElement('textarea')
    eleTextarea.style.width = 0
    eleTextarea.style.position = 'fixed'
    eleTextarea.style.left = '-999px'
    eleTextarea.style.top = '10px'
    eleTextarea.setAttribute('readonly', 'readonly')
    document.body.appendChild(eleTextarea)
  }

  var funCopy = function (text, callback) {
    callback = callback || function () {}

    if (!isFallback) {
      navigator.clipboard.writeText(text).then(
        function () {
          callback()
          // 成功回调
          success(text)
        },
        function () {
          // 禁止写入剪切板后使用兜底方法
          copyText(text, false)
          callback()
          // 成功回调
          success(text)
        }
      )

      return
    }

    eleTextarea.value = text
    eleTextarea.select()
    document.execCommand('copy', true)

    callback()
    // 成功回调
    success(text)
  }

  // 提示复制成功的方法
  // 对外可访问
  copyText.tips = function (event) {
    if (!event) {
      return
    }
    // 复制成功提示
    var eleTips = document.createElement('span')
    eleTips.className = 'text-popup'
    eleTips.innerHTML = '复制成功'
    document.body.appendChild(eleTips)
    // 事件
    eleTips.addEventListener('animationend', function () {
      eleTips.parentNode.removeChild(eleTips)
    })
    // For IE9
    if (!history.pushState) {
      setTimeout(function () {
        eleTips.parentNode.removeChild(eleTips)
      }, 1000)
    }

    eleTips.style.left = event.pageX - eleTips.clientWidth / 2 + 'px'
    eleTips.style.top = event.pageY - eleTips.clientHeight + 'px'
  }

  var strStyle =
    '.text-popup { animation: textPopup 1s both; -ms-transform: translateY(-20px); color: #01cf97; user-select: none; white-space: nowrap; position: absolute; z-index: 99; }@keyframes textPopup {0%, 100% { opacity: 0; } 5% { opacity: 1; } 100% { transform: translateY(-50px); }}'

  var eleStyle = document.querySelector('#popupStyle')
  if (!eleStyle) {
    eleStyle = document.createElement('style')
    eleStyle.id = 'popupStyle'
    eleStyle.innerHTML = strStyle
    document.head.appendChild(eleStyle)
  }

  if (!button) {
    funCopy(content)
    return
  }

  // 事件绑定
  button.addEventListener('click', function (event) {
    var strCopy = content
    if (content && content.tagName) {
      strCopy = content.textContent || content.value
    }
    // 复制的文字内容
    if (!strCopy) {
      return
    }

    funCopy(strCopy, function () {
      copyText.tips(event)
    })
  })
}