如何在 JavaScript 中复制到剪贴板?

IT技术 javascript clipboard copy-paste
2020-12-31 22:35:56

将文本复制到剪贴板(多浏览器)的最佳方法是什么?

我试过了:

function copyToClipboard(text) {
    if (window.clipboardData) { // Internet Explorer
        window.clipboardData.setData("Text", text);
    } else {
        unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
        const clipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
        clipboardHelper.copyString(text);
    }
}

但在 Internet Explorer 中,它会出现语法错误。在 Firefox 中,它说unsafeWindow is not defined

一个不使用Flash 的好方法Trello 如何访问用户的剪贴板?

6个回答

概述

有三个主要的浏览器 API 可用于复制到剪贴板:

  1. 异步剪贴板 API [navigator.clipboard.writeText]

    • Chrome 66 中提供以文本为中心的部分(2018 年 3 月)
    • 访问是异步的并使用JavaScript Promises,可以这样编写,以便安全用户提示(如果显示)不会中断页面​​中的 JavaScript。
    • 文本可以直接从变量复制到剪贴板。
    • 仅支持通过 HTTPS 提供服务的页面。
    • 在 Chrome 66 页面中,非活动选项卡可以在没有权限提示的情况下写入剪贴板。
  2. document.execCommand('copy')已弃用)👎

    • 截至 2015 年 4 月,大多数浏览器都支持此功能(请参阅下面的浏览器支持)。
    • 访问是同步的,即停止页面中的 JavaScript,直到完成包括显示和用户与任何安全提示交互。
    • 文本从 DOM 中读取并放置在剪贴板上。
    • 在 2015 年 4 月的测试期间,只有 Internet Explorer 被记录为在写入剪贴板时显示权限提示。
  3. 覆盖复制事件

    • 请参阅关于覆盖复制事件的剪贴板 API 文档
    • 允许您从任何复制事件修改剪贴板上显示的内容,可以包括纯文本以外的其他格式的数据。
    • 此处未涵盖,因为它不直接回答问题。

一般开发说明

在控制台中测试代码时,不要指望剪贴板相关的命令可以工作。通常,页面需要处于活动状态(异步剪贴板 API)或需要用户交互(例如用户单击)以允许 ( document.execCommand('copy')) 访问剪贴板,请参见下文了解更多详细信息。

重要事项(此处注明 2020/02/20)

请注意,由于这篇文章最初是针对跨源IFRAME和其他IFRAME“沙箱”中的权限编写的,因此阻止了嵌入式演示的“运行代码片段”按钮和“codepen.io 示例”在某些浏览器(包括 Chrome 和 Microsoft Edge)中工作)。

要开发创建您自己的网页,请通过 HTTPS 连接提供该页面以进行测试和开发。

这是一个演示代码工作的测试/演示页面:https : //deanmarktaylor.github.io/clipboard-test/

异步 + 回退

由于浏览器对新的 Async Clipboard API 的支持级别,您可能希望回退到该document.execCommand('copy')方法以获得良好的浏览器覆盖率。

这是一个简单的示例(可能无法嵌入本站点,请阅读上面的“重要”注释):

function fallbackCopyTextToClipboard(text) {
  var textArea = document.createElement("textarea");
  textArea.value = text;
  
  // Avoid scrolling to bottom
  textArea.style.top = "0";
  textArea.style.left = "0";
  textArea.style.position = "fixed";

  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Fallback: Copying text command was ' + msg);
  } catch (err) {
    console.error('Fallback: Oops, unable to copy', err);
  }

  document.body.removeChild(textArea);
}
function copyTextToClipboard(text) {
  if (!navigator.clipboard) {
    fallbackCopyTextToClipboard(text);
    return;
  }
  navigator.clipboard.writeText(text).then(function() {
    console.log('Async: Copying to clipboard was successful!');
  }, function(err) {
    console.error('Async: Could not copy text: ', err);
  });
}

var copyBobBtn = document.querySelector('.js-copy-bob-btn'),
  copyJaneBtn = document.querySelector('.js-copy-jane-btn');

copyBobBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Bob');
});


copyJaneBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Jane');
});
<div style="display:inline-block; vertical-align:top;">
  <button class="js-copy-bob-btn">Set clipboard to BOB</button><br /><br />
  <button class="js-copy-jane-btn">Set clipboard to JANE</button>
</div>
<div style="display:inline-block;">
  <textarea class="js-test-textarea" cols="35" rows="4">Try pasting into here to see what you have on your clipboard:

  </textarea>
</div>

(codepen.io 示例可能不起作用,请阅读上面的“重要”注释)请注意,此代码段在 Stack Overflow 的嵌入式预览中效果不佳,您可以在此处尝试:https ://codepen.io/DeanMarkTaylor/pen/RMRaJX?editors =1011

异步剪贴板 API

请注意,可以通过 Chrome 66 中的权限 API 来“请求权限”并测试对剪贴板的访问权限。

var text = "Example text to appear on clipboard";
navigator.clipboard.writeText(text).then(function() {
  console.log('Async: Copying to clipboard was successful!');
}, function(err) {
  console.error('Async: Could not copy text: ', err);
});

document.execCommand('复制')

这篇文章的其余部分将介绍document.execCommand('copy')API的细微差别和细节

浏览器支持

JavaScriptdocument.execCommand('copy')支持有所增加,请参阅以下浏览器更新链接:已弃用)👎

简单示例

(可能无法嵌入本网站,请阅读上面的“重要”说明)

var copyTextareaBtn = document.querySelector('.js-textareacopybtn');

copyTextareaBtn.addEventListener('click', function(event) {
  var copyTextarea = document.querySelector('.js-copytextarea');
  copyTextarea.focus();
  copyTextarea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
  } catch (err) {
    console.log('Oops, unable to copy');
  }
});
<p>
  <button class="js-textareacopybtn" style="vertical-align:top;">Copy Textarea</button>
  <textarea class="js-copytextarea">Hello I'm some text</textarea>
</p>

复杂示例:复制到剪贴板而不显示输入

如果屏幕上有一个textareaorinput元素可见,上面的简单示例效果很好

在某些情况下,您可能希望将文本复制到剪贴板而不显示input/textarea元素。这是解决此问题的方法的一个示例(基本上是插入一个元素,复制到剪贴板,删除元素):

使用 Google Chrome 44、Firefox 42.0a1 和 Internet Explorer 11.0.8600.17814 进行测试。

(可能无法嵌入本网站,请阅读上面的“重要”说明)

function copyTextToClipboard(text) {
  var textArea = document.createElement("textarea");

  //
  // *** This styling is an extra step which is likely not required. ***
  //
  // Why is it here? To ensure:
  // 1. the element is able to have focus and selection.
  // 2. if the element was to flash render it has minimal visual impact.
  // 3. less flakyness with selection and copying which **might** occur if
  //    the textarea element is not visible.
  //
  // The likelihood is the element won't even render, not even a
  // flash, so some of these are just precautions. However in
  // Internet Explorer the element is visible whilst the popup
  // box asking the user for permission for the web page to
  // copy to the clipboard.
  //

  // Place in the top-left corner of screen regardless of scroll position.
  textArea.style.position = 'fixed';
  textArea.style.top = 0;
  textArea.style.left = 0;

  // Ensure it has a small width and height. Setting to 1px / 1em
  // doesn't work as this gives a negative w/h on some browsers.
  textArea.style.width = '2em';
  textArea.style.height = '2em';

  // We don't need padding, reducing the size if it does flash render.
  textArea.style.padding = 0;

  // Clean up any borders.
  textArea.style.border = 'none';
  textArea.style.outline = 'none';
  textArea.style.boxShadow = 'none';

  // Avoid flash of the white box if rendered for any reason.
  textArea.style.background = 'transparent';


  textArea.value = text;

  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
  } catch (err) {
    console.log('Oops, unable to copy');
  }

  document.body.removeChild(textArea);
}


var copyBobBtn = document.querySelector('.js-copy-bob-btn'),
  copyJaneBtn = document.querySelector('.js-copy-jane-btn');

copyBobBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Bob');
});


copyJaneBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Jane');
});
<div style="display:inline-block; vertical-align:top;">
  <button class="js-copy-bob-btn">Set clipboard to BOB</button><br /><br />
  <button class="js-copy-jane-btn">Set clipboard to JANE</button>
</div>
<div style="display:inline-block;">
  <textarea class="js-test-textarea" cols="35" rows="4">Try pasting into here to see what you have on your clipboard:

  </textarea>
</div>

补充说明

仅当用户采取行动时才有效

所有document.execCommand('copy')调用都必须作为用户操作的直接结果发生,例如单击事件处理程序。这是一种防止在用户不期望的情况下弄乱剪贴板的措施。

有关详细信息,请参阅此处Google Developers 帖子

剪贴板 API

请注意,可以在此处找到完整的剪贴板 API 草案规范:https : //w3c.github.io/clipboard-apis/

是否支持?

  • document.queryCommandSupported('copy')true如果命令“受浏览器支持”,则应返回
  • document.queryCommandEnabled('copy')返回true如果document.execCommand('copy')会成功,如果现在叫。检查以确保从用户启动的线程调用命令并满足其他要求。

然而,作为浏览器兼容性问题的一个例子,从 2015 年 4 月到 10 月的 Google Chrome 浏览器只有在truedocument.queryCommandSupported('copy')用户启动的线程调用命令时才返回

请注意下面的兼容性详细信息。

浏览器兼容性详情

虽然对document.execCommand('copy')包装在try/catch块中的简单调用作为用户单击的结果调用将使您获得最大的兼容性,但以下有一些限制条件:

document.execCommand, document.queryCommandSupportedor 的任何调用document.queryCommandEnabled都应包含在try/catch块中。

不同的浏览器实现和浏览器版本在调用而不是返回时会抛出不同类型的异常false

不同的浏览器实现仍在不断变化,剪贴板 API仍在草案中,所以请记住进行测试。

目前全球 91% 的用户都支持剪贴板 API:caniuse.com/mdn-api_clipboard_writetext
2021-02-17 22:35:56
我只是在回退后添加了焦点的重置: var previousFocusElement = document.activeElement (....all the fallback code...) previousFocusElement.focus();
2021-02-17 22:35:56
@tnkh 当然可以,但替代品(剪贴板 API)尚未完全成熟和受支持。
2021-02-28 22:35:56
关于样式的注意事项:我只是opacity: 0用来隐藏<textarea>. 另外z-index:-1,如果您想感到完全安全。所以我们实际上只需要定义三个样式属性:position: fixed以及前面提到的两个。
2021-03-05 22:35:56
很抱歉破坏聚会,但是document.execCommand is obsolete参见developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
2021-03-07 22:35:56

自动复制到剪贴板可能很危险,因此大多数浏览器(Internet Explorer 除外)都非常困难。就个人而言,我使用以下简单的技巧:

function copyToClipboard(text) {
  window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
}

用户将看到提示框,其中已选择要复制的文本。现在按Ctrl+CEnter(关闭框)就足够了——瞧!

现在剪贴板复制操作是安全的,因为用户手动执行(但以非常简单的方式)。当然,它适用于所有浏览器。

<button id="demo" onclick="copyToClipboard(document.getElementById('demo').innerHTML)">This is what I want to copy</button>

<script>
  function copyToClipboard(text) {
    window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
  }
</script>

将“提示”功能更改为自定义模式是微不足道的,技巧的核心是使用可编辑的内容字段并预选文本,并且不会通过强制用户使用自己行动。A++
2021-02-17 22:35:56
如果您的文本超过 2000 个字符,它将被截断,但对于较小的文本样本,它效果很好
2021-02-17 22:35:56
但是该对话框中显示的字符数是有限制的,因此要复制的数据量是有限制的。
2021-02-20 22:35:56
聪明,但这只支持单行。
2021-02-21 22:35:56
@RasTheDestroyer - 2k 字符的截断似乎是 Chrome 的问题,但无论如何知道它是件好事
2021-03-05 22:35:56

以下方法适用于 Chrome、Firefox、Internet Explorer 和 Edge,以及最新版本的 Safari(在 2016 年 10 月发布的版本 10 中添加了复制支持)。

  • 创建一个 textarea 并将其内容设置为要复制到剪贴板的文本。
  • 将 textarea 附加到 DOM。
  • 选择文本区域中的文本。
  • 调用 document.execCommand("copy")
  • 从 dom 中删除 textarea。

注意:您不会看到 textarea,因为它是在 Javascript 代码的同一个同步调用中添加和删除的。

如果您自己实施此操作,则需要注意以下事项:

  • 出于安全原因,这只能从事件处理程序调用,例如单击(就像打开窗口一样)。
  • Internet Explorer 将在第一次更新剪贴板时显示一个权限对话框。
  • Internet Explorer 和 Edge 将在 textarea 获得焦点时滚动。
  • execCommand() 在某些情况下可能会抛出异常。
  • 除非您使用 textarea,否则换行符和制表符可能会被吞下。(大多数文章似乎都推荐使用 div)
  • 当 Internet Explorer 对话框显示时,textarea 将是可见的,您需要隐藏它,或者使用 Internet Explorer 特定的 clipboardData API。
  • 在 Internet Explorer 系统管理员可以禁用剪贴板 API。

下面的函数应该尽可能干净地处理以下所有问题。如果您发现任何问题或有任何改进建议,请发表评论。

// Copies a string to the clipboard. Must be called from within an
// event handler such as click. May return false if it failed, but
// this is not always possible. Browser support for Chrome 43+,
// Firefox 42+, Safari 10+, Edge and Internet Explorer 10+.
// Internet Explorer: The clipboard feature may be disabled by
// an administrator. By default a prompt is shown the first
// time the clipboard is used (per session).
function copyToClipboard(text) {
    if (window.clipboardData && window.clipboardData.setData) {
        // Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
        return window.clipboardData.setData("Text", text);

    }
    else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
        var textarea = document.createElement("textarea");
        textarea.textContent = text;
        textarea.style.position = "fixed";  // Prevent scrolling to bottom of page in Microsoft Edge.
        document.body.appendChild(textarea);
        textarea.select();
        try {
            return document.execCommand("copy");  // Security exception may be thrown by some browsers.
        }
        catch (ex) {
            console.warn("Copy to clipboard failed.", ex);
            return false;
        }
        finally {
            document.body.removeChild(textarea);
        }
    }
}

https://jsfiddle.net/fx6a6n6x/

@SantiagoCorredoira:在 2016 年,这应该是公认的答案。请考虑重新分配 BGT(绿色大勾)。
2021-02-10 22:35:56
@Noitidart 我测试过,它非常适用于 firefox 54、chrome 60 和边缘浏览器,即使焦点不在 html 文档中,您遇到的错误也可能特定于 FF 55 版本
2021-02-22 22:35:56
jQuery UI 用户:请注意,如果您尝试从模式对话框中使用此功能,则会遇到此方法的问题。我怀疑这是因为 jQuery UI 模式正在管理/操作文档焦点。如果它适合您的用例,一种解决方法是先关闭模态对话框,然后复制文本。或者,简单地使用非模态对话框。我怀疑您也可以修改此功能,以便将 textarea 添加到模态而不是正文中。
2021-02-27 22:35:56
@Noitidart 它在这里仍然可以完美运行,专注于开发工具并没有阻止它。顺便说一句,普通的 Web 应用程序用户会在开发人员工具上做什么
2021-03-03 22:35:56
不错的答案:跨浏览器支持、错误处理 + 清理。截至今天对 queryCommandSupported 的新支持,复制到剪贴板现在在 Javascript 中是可行的,这应该是公认的答案,而不是笨拙的 'window.prompt("Copy to clipboard: Ctrl+C, Enter", text)' 解决方法。window.clipboardData 支持IE9,所以你应该在浏览器支持列表中添加IE9,我想也许IE8和以前的也可以,但需要验证。
2021-03-04 22:35:56

这是我对那个的看法......

function copy(text) {
    var input = document.createElement('input');
    input.setAttribute('value', text);
    document.body.appendChild(input);
    input.select();
    var result = document.execCommand('copy');
    document.body.removeChild(input);
    return result;
 }

@korayem:请注意,使用 htmlinput字段不会考虑换行符,\n并且会将任何文本拼合为一行。

正如@nikksan 在评论中提到的,使用textarea将解决问题如下:

function copy(text) {
    var input = document.createElement('textarea');
    input.innerHTML = text;
    document.body.appendChild(input);
    input.select();
    var result = document.execCommand('copy');
    document.body.removeChild(input);
    return result;
}
我已经复制了你的答案。它适用于 chrome,这就是我所需要的。
2021-02-23 22:35:56
在 Win10x64 上的 Microsoft Edge 42.17134.1.0 中不起作用
2021-03-02 22:35:56
出于某种原因,我通常的“创建一个隐藏的输入或文本区域,然后选择它并执行命令”不起作用,这是迄今为止这里列出的最佳解决方案,尽管其他解决方案很全面并且像完整的维基百科页面,但这个运行良好对我来说,所以+1
2021-03-02 22:35:56
@sof-03 使用 textarea 而不是 input 并添加\r\n换行符
2021-03-03 22:35:56
这是适用于 Firefox v68.0.2(64 位)的最简单的解决方案。
2021-03-07 22:35:56

从网页读取和修改剪贴板会引起安全和隐私问题。但是,在 Internet Explorer 中,可以这样做。我找到了这个示例片段

    <script type="text/javascript">
        function select_all(obj) {
            var text_val=eval(obj);
            text_val.focus();
            text_val.select();
            r = text_val.createTextRange();
            if (!r.execCommand) return; // feature detection
            r.execCommand('copy');
        }
    </script>
    <input value="http://www.sajithmr.com"
     onclick="select_all(this)" name="url" type="text" />

请解释一下是什么execCommand(\\’copy\\’);,如果不是复制到 IE 的剪贴板?@博尔纳先生
2021-02-15 22:35:56
当人们使用 Flash 更改剪贴板时,为什么这些隐私问题十年来从未被提出?如果我们只允许一种方式(即复制,而不是阅读其内容),这将如何产生隐私问题?
2021-02-23 22:35:56
不要使用if(!document.all)if(!r.execCommand)以免其他人实施它!Document.all 与此完全无关。
2021-02-27 22:35:56
@MuhammadbinYusrat:虽然不是隐私问题,但它UX 问题。考虑到用户复制了一些东西并认为他知道剪贴板上的内容,然后浏览您的网站,突然剪贴板包含一些他没有要求的东西,他首先丢失了他复制的内容。
2021-03-04 22:35:56
使用 flash 进行简单的复制操作似乎有点矫枉过正,很高兴有一种干净的 JS 方法可以做到这一点。而且由于我们处于企业环境中。IE 没问题。谢谢班迪!
2021-03-08 22:35:56