如何在 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/02/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');
});
<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('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');
}
});
<p>
<button class="js-textareacopybtn" style="vertical-align:top;">Copy Textarea</button>
<textarea class="js-copytextarea">Hello I'm some text</textarea>
</p>
复杂示例:复制到剪贴板而不显示输入
如果屏幕上有可见的
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');
});
<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 开发者帖子 。
剪贴板 API
请注意,完整的剪贴板 API 草案规范可在此处找到: https://w3c.github.io/clipboard-apis/
是否支持?
-
document.queryCommandSupported('copy')
应返回true
,如果命令“受浏览器支持”。 -
并且如果现在调用
document.execCommand('copy')
成功,则document.queryCommandEnabled('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 仍处于草稿阶段,因此请记得进行测试。
自动复制到剪贴板可能会很危险,因此大多数浏览器(Internet Explorer 除外)都很难实现。我个人使用以下简单技巧:
function copyToClipboard(text) {
window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
}
系统会向用户显示提示框,其中要复制的文本已被选中。现在只需按 Ctrl + C 和 Enter (关闭提示框)即可 - 瞧!
现在剪贴板复制操作 安全 ,因为用户是手动执行的(但方式非常简单)。当然,它适用于所有浏览器。
<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>
以下方法适用于 Chrome、Firefox、Internet Explorer 和 Edge,以及 Safari 的最新版本(2016 年 10 月发布的版本 10 中添加了复制支持)。
- 创建一个文本区域并将其内容设置为要复制到剪贴板的文本。
- 将文本区域附加到 DOM。
- 选择文本区域中的文本。
- 调用 document.execCommand("copy")
- 从 dom 中删除文本区域。
注意:您将看不到文本区域,因为它是在同一个同步调用 Javascript 代码中添加和删除的。
如果您自己实现此功能,请注意以下几点:
- 出于安全原因,这只能从事件处理程序(例如单击)调用(就像打开窗口一样)。
- Internet Explorer 将显示权限对话框剪贴板首次更新时。
- 当文本区域获得焦点时,Internet Explorer 和 Edge 将会滚动。
- 在某些情况下,execCommand() 可能会抛出异常。
- 除非使用文本区域,否则换行符和制表符可能会被吞没。(大多数文章似乎建议使用 div)
- 显示 Internet Explorer 对话框时,文本区域将可见,您需要隐藏它,或者使用 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 prompt("Copy to clipboard: Ctrl+C, Enter", text);
}
finally {
document.body.removeChild(textarea);
}
}
}