如何在JavaScript中复制到剪贴板?
总览
有三个主要的浏览器API可以用于复制到剪贴板:
-
异步剪贴板API
[navigator.clipboard.writeText]
- 在Chrome 66(2018年3月)中提供了针对文本的部分。
- 访问是异步的,并使用JavaScript Promises,可以编写使安全用户提示(如果显示)不会中断页面中的JavaScript的代码。
- 文本可以直接从变量复制到剪贴板。
- 仅支持通过HTTPS提供的页面。
- 在Chrome 66中,处于非活动标签页的页面可以在不需要权限提示的情况下写入剪贴板。
-
document.execCommand('copy')
(已弃用)- 大多数浏览器从2015年4月左右开始支持此功能(请参见以下的浏览器支持)。
- 访问是同步的,即在完成拷贝操作之前包括显示和用户与任何安全提示的交互,JavaScript代码会停止在页面中。
- 文本从DOM中读取并放置到剪贴板中。
- 在2015年4月的测试中,只有Internet Explorer显示了在写入剪贴板时显示权限提示的情况。
-
覆盖复制事件
- 请参见剪贴板API文档中有关覆盖复制事件的内容。
- 允许您修改从任何复制事件出现在剪贴板上的内容,可以包括其他格式的数据,而不仅仅是纯文本。
- 这里没有详细介绍,因为它不能直接回答问题。
一般开发注意事项
不要期望在控制台测试代码时剪贴板相关的命令可以正常工作。一般而言,该页面必须处于活动状态(异步剪贴板API)或需要用户交互(例如用户点击)才能访问剪贴板(document.execCommand('copy')
)) 有关更多详细信息,请参见下文。
重要提示(2020年2月20日更新)
请注意,自从本文最初发布以来,跨源IFrame权限的停用和其他IFrame“沙盒化”导致嵌入的演示“运行代码片段”按钮和“codepen.io示例”无法在一些浏览器(包括Chrome和Microsoft Edge)中运行。
为了开发创建您自己的网页,请通过HTTPS连接提供该页面以进行测试和开发。
这里有一个测试/演示页面,展示了代码的运行:
https://deanmarktaylor.github.io/clipboard-test/
异步+后备
由于新的异步剪贴板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'); });
(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('copy')
这篇文章的其余部分详细介绍了document.execCommand('copy')
API的细微差别和详细信息。
浏览器支持
JavaScript(已被废弃)document.execCommand('copy')
支持已经增加了,有关浏览器更新的链接如下:
- Internet Explorer 10+(虽然此文档表明,从Internet Explorer 5.5+开始就有一些支持)。
- Google Chrome 43+(~2015年4月)
- Mozilla Firefox 41+(~2015年9月)
- Opera 29+(基于Chromium 42,~2015年4月)
简单示例
(在此网站中嵌入可能无法正常工作,请阅读上面的“注意”)
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'); } });
复杂示例:将文本复制到剪贴板而不显示输入框
上面的简单示例适用于屏幕上有textarea
或input
元素的情况。
在某些情况下,您可能希望在不显示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'); });
其他注意事项
仅在用户执行操作时起作用
所有 document.execCommand('copy')
调用必须作为用户操作的直接结果,例如 click 事件处理程序。这是为了防止在用户不期望的情况下破坏其剪贴板。
有关更多信息,请参见此处的 Google 开发人员文章。
剪贴板 API
请注意,完整的剪贴板 API 草案规范可在此处找到:
https://w3c.github.io/clipboard-apis/
是否被支持?
document.queryCommandSupported('copy')
如果“浏览器支持该命令”,则应返回true
。- 而
document.queryCommandEnabled('copy')
如果现在调用document.execCommand('copy')
将成功,则也返回true
。检查以确保命令是从用户发起的线程中调用,并满足其他要求。
然而,作为浏览器兼容性问题的一个示例,从大约 2015 年 4 月到 10 月,Google Chrome 仅在从用户发起的线程中调用命令时才从 document.queryCommandSupported('copy')
中返回 true
。
请注意下方的兼容性细节。
浏览器兼容性详解
虽然简单地调用document.execCommand('copy')
,并将其包装在try
/catch
块中,作为用户单击的结果,可以获得最兼容性的使用,但以下的情况有一些注意点:
任何对document.execCommand
、document.queryCommandSupported
或document.queryCommandEnabled
的调用都应该被包装在try
/catch
块中。
不同的浏览器实现和浏览器版本在调用时会抛出不同类型的异常,而不是返回false
。
不同的浏览器实现仍处于不断变化之中,Clipboard API仍然处于起草阶段,因此请记得进行测试。