- Published on
如何在JavaScript中将文本复制到剪贴板
- Authors
- Name
在现代Web开发中,能够将文本复制到剪贴板是一个常见的需求。本文将详细介绍三种在JavaScript中实现这一功能的方法,包括异步剪贴板API和document.execCommand('copy')
,以及覆盖复制事件。
概述
用于复制到剪贴板的主要浏览器API有以下三种:
异步剪贴板API
[navigator.clipboard.writeText]
- 该API的文本部分在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与回退方法
由于异步剪贴板API的浏览器支持水平,您可能需要回退到document.execCommand('copy')
方法以确保良好的浏览器覆盖率。
下面是一个简单的示例(在此站点嵌入时可能无法工作,请阅读上面的“重要提示”):
function fallbackCopyTextToClipboard(text) {
var textArea = document.createElement('textarea')
textArea.value = text
// 避免滚动到底部
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>
可以在这里尝试:https://codepen.io/DeanMarkTaylor/pen/RMRaJX?editors=1011
异步剪贴板API
请注意,可以通过权限API在Chrome 66中“请求权限”并测试剪贴板访问。
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')
//
// *** 这一步额外的样式设置可能不是必须的。 ***
//
// 为什么要这样做?为了确保:
// 1. 该元素能够获得焦点和选择。
// 2. 如果该元素闪烁呈现,它的视觉影响最小。
// 3. 尽量减少选择和复制时可能出现的不稳定性 **可能**
// 在元素不可见时发生。
//
// 可能这些元素不会呈现,甚至不会闪烁,所以有些只是预防措施。
// 但是在Internet Explorer中,元素会在弹出框
// 要求用户允许网页复制到剪贴板时显示。
//
// 无论滚动位置如何,放置在屏幕的左上角。
textArea.style.position = 'fixed'
textArea.style.top = 0
textArea.style.left = 0
// 确保它的宽度和高度很小。设置为1px / 1em
// 在某些浏览器中无法工作。
textArea.style.width = '2em'
textArea.style.height = '2em'
// 我们不需要填充,减少如果闪烁呈现时的大小。
textArea.style.padding = 0
// 清理任何边框。
textArea.style.border = 'none'
textArea.style.outline = 'none'
textArea.style.boxShadow = 'none'
// 如果由于任何原因呈现时避免白框闪烁。
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')
调用必须作为用户操作的直接结果,例如点击事件处理程序。这是为了防止未预期的操作干扰用户的剪贴板。
看到谷歌开发者的帖子了解更多信息。
剪贴板API
请注意可以在这里找到完整的剪贴板API草案规范:https://w3c.github.io/clipboard-apis/
是否支持?
document.queryCommandSupported('copy')
应该返回true
,如果命令“受浏览器支持”。- 而
document.queryCommandEnabled('copy')
返回true
,如果document.execCommand('copy')
调用现在成功。
但是,作为浏览器兼容性问题的示例,从2015年4月至2015年10月,如果命令是从用户发起的线程调用,Google Chrome仅从document.queryCommandSupported('copy')
返回true
。
请查看下面的兼容性详情。
浏览器兼容性详情
尽管简单地将document.execCommand('copy')
封装在一个try
/catch
块中,作为用户点击的结果调用可以获得最好的兼容性,使用以下方法有一些注意事项:
任何对document.execCommand
,document.queryCommandSupported
或document.queryCommandEnabled
的调用都应封装在一个try
/catch
块中。
不同的浏览器实现和浏览器版本在调用时抛出不同类型的异常,而不是返回false
。
不同的浏览器实现仍在变化,剪贴板API仍然是草案,请记得进行测试。