前端复制文本到剪贴板

2,547 阅读1分钟

1. 使用的到API

  1. document.execCommand
  2. Async Clipboard API

2. 具体实现

1. 功能实现

<div class="copy-input">
    <input id="copy-input" type="text" readonly value="http://www.baidu.com">
    <button onclick="copyInput()">copy</button>
</div>

<script>
    async function copyInput () {
      const inputDom = document.querySelector("#copy-input");

      try {
        return await navigator.clipboard.writeText(inputDom.value);
      } catch (error) {
        console.error(error);
      }

      const selected =
        document.getSelection().rangeCount > 0
          ? document.getSelection().getRangeAt(0)
          : false;

      inputDom.focus();
      inputDom.select();
      document.execCommand("copy");
      inputDom.setSelectionRange(0, 0);
      inputDom.blur();

      if (selected) {
        document.getSelection().removeAllRanges();
        document.getSelection().addRange(selected);
      }
    }
</script>

2. 实现一个复制文本到剪贴板函数。

copyToClipboard 的基础上加上了 navigator.clipboard.writeText 的调用。

  • 新建一个 <textarea>元素,把要复制的内容赋值给它,将其添加到HTML文档中。
  • 调用 document.getSelection() 缓存用户已经选择(如果有的话)的内容。
  • 使用 document.execCommand('copy') 复制到剪贴板。
  • 从HTML文档中删除 <textarea> 元素。
  • 使用 Selection.addRange() 恢复原始选择的范围。
const copyToClipboard = async str => {
  try {
    return await navigator.clipboard.writeText(str);
  } catch (error) {
    console.error(error);
  }

  const el = document.createElement('textarea');
  el.value = str;
  el.setAttribute('readonly', '');
  el.style.position = 'absolute';
  el.style.left = '-9999px';
  document.body.appendChild(el);
  const selected =
    document.getSelection().rangeCount > 0
      ? document.getSelection().getRangeAt(0)
      : false;
  el.select();
  document.execCommand('copy');
  document.body.removeChild(el);
  if (selected) {
    document.getSelection().removeAllRanges();
    document.getSelection().addRange(selected);
  }
};

3. 扩展-复制图片

// https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem
async function writeClipImg() {
  try {
    const imgURL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg';
    const data = await fetch(imgURL);
    const blob = await data.blob();

    await navigator.clipboard.write([
      new ClipboardItem({
        [blob.type]: blob
      })
    ]);
    console.log('Fetched image copied.');
  } catch(err) {
    console.error(err.name, err.message);
  }
}

参考文档

  1. 提到了编辑器 execCommand的问题以及替代方案思考
  2. 阮一峰 剪贴板操作 Clipboard API 教程
  3. 30-seconds-of-code copyToClipboard
  4. npm package Copy to clipboard
  5. VS Code 【BrowserClipboardService】