在日常业务开发,比如复制后增加版权信息,点击复制,等场景中需要进行复制粘贴的操作,以下是几种实现方案。
Clipboard API
Clipboard API 提供了响应剪贴板命令(剪切、复制和粘贴)与异步读写系统剪贴板的能力。从权限 API (Permissions API) 获取权限之后,才能访问剪贴板内容;如果用户没有授予权限,则不允许读取剪贴板内容。
可以使用全局的 Navigator.clipboard 来访问剪贴板。
Navigator.clipboard 属性返回 Clipboard 对象,所有操作都通过这个对象进行。
Clipboard 对象提供了四个方法,用来读写剪贴板。它们都是异步方法,返回 Promise 对象。
read( ) 方法
read()
方法可以从剪贴板读取任意数据,可以是文本数据,也可以是二进制数据(比如图片)。该方法需要用户明确给予许可。
read()
方法返回一个 Promise
对象。一旦该对象的状态变为 resolved
,就可以获得一个数组,每个数组成员都是 ClipboardItem 对象的实例。
ClipboardItem 对象表示一个单独的剪贴项,每个剪贴项都拥有 types
属性和 getType( )
方法。
ClipboardItem.types
属性返回一个数组,里面的成员是该剪贴项可用的 MIME
类型,比如某个剪贴项可以用 HTML
格式粘贴,也可以用纯文本格式粘贴,那么它就有两个 MIME
类型(text/html
和 text/plain
)。
ClipboardItem.getType(type)
方法用于读取剪贴项的数据,返回一个 Promise
对象。该方法接受剪贴项的 MIME
类型作为参数,返回该类型的数据,该参数是必需的,否则会报错。
示例:
//获取权限
navigator.permissions
.query({
name: 'clipboard-read'
})
.then(result => {
if (result.state == 'granted' || result.state == 'prompt') {
//读取剪贴板
navigator.clipboard.read().then(data => {
console.log(data)
})
} else {
alert('请允许读取剪贴板!')
}
})
readText( ) 方法
readText()
方法可以从剪贴板读取文本内容。该方法需要用户明确给予许可。
示例:
//获取权限
navigator.permissions
.query({
name: 'clipboard-read'
})
.then(result => {
if (result.state == 'granted' || result.state == 'prompt') {
//读取剪贴板
navigator.clipboard.readText().then(text => {
console.log(text)
})
} else {
alert('请允许读取剪贴板!')
}
})
write( ) 方法
write()
方法可以将任意数据写入剪贴板,可以是文本数据,也可以是二进制数据。该方法不需要用户许可。
write()
方法接受一个 ClipboardItem 实例作为参数,表示写入剪贴板的数据。
示例:
//写入一张图片
const imgURL = 'https://dummyimage.com/300.png'
const data = await fetch(imgURL)
const blob = await data.blob()
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob
})
])
注意,Chrome 浏览器目前只支持写入 PNG 格式的图片。
writeText( ) 方法
writeText()
方法可以写入文本内容至剪贴板。该方法不需要用户许可。
示例:
navigator.clipboard.writeText('写入剪贴板文本内容')
安全限制
由于用户可能把敏感数据(比如密码)放在剪贴板,允许脚本任意读取会产生安全风险,所以这个 API 的安全限制比较多。
首先,Chrome 浏览器规定,只有 HTTPS 协议的页面才能使用这个 API。不过,开发环境(localhost
)允许使用非加密协议。
其次,调用时需要明确获得用户的许可。权限的具体实现使用了 Permissions API ,跟剪贴板相关的有两个权限:clipboard-write
(写权限)和 clipboard-read
(读权限)。“写权限”自动授予脚本,而“读权限”必须用户明确同意给予。也就是说,写入剪贴板,脚本可以自动完成,但是读取剪贴板时,浏览器会弹出一个对话框,询问用户是否同意读取。
Document.execCommand()
这个 API 已弃用,不推荐使用它,但是为了兼容还是了解一下吧。
document.execCommand()
方法用于操纵可编辑区域的内容。
document.execCommand('copy')
document.execCommand('copy')
实现复制操作
示例:
const copyBtn = document.querySelector('#copyBtn');
const copyContent = document.querySelector('#copyContent');
// 复制操作要放在事件监听函数里面,由用户触发(比如用户点击按钮)。
copyBtn.addEventListener('click', () => {
copyContent.select();
document.execCommand('copy');
})
document.execCommand('paste')
document.execCommand('paste')
实现粘贴操作
示例:
const pasteText = document.querySelector('#paste');
pasteText.focus();
document.execCommand('paste');
Chrome、Firefox 不支持 document.execCommand('paste')
clipboard.js
除了使用原生 JS 外,还可以使用一些第三方的库,比如 clipboard.js 来实现复制文本到剪贴板的操作。
安装
npm install clipboard --save
使用
1、用一个元素当触发器来复制另一个元素的文本,需要传递 DOM
选择器,HTML
元素或 HTML
元素列表来实例化它。
2、在触发器元素上添加 data-clipboard-target
属性,该属性值是一个元素选择器,用来匹配另一个需要被复制的元素。
示例:
需要被复制的内容
//触发器
var clipboard = new ClipboardJS('#copyBtn')
clipboard.on('success', function (e) {
console.log('复制成功!')
console.log('操作文本内容:', e.text)
console.log('触发操作的DOM元素:', e.trigger)
e.clearSelection()
})
clipboard.on('error', function (e) {
console.log('复制失败')
console.log('触发操作的DOM元素:', e.trigger)
})
另外,触发器元素上也可以定义 data-clipboard-action
属性为 copy
或 cut
,来明确操作是复制还是剪切,如果忽略了这个属性,则默认是复制。值为 cut
时仅适用于 input
或 textarea
元素。
//触发器
var clipboard = new ClipboardJS('#copyBtn')
clipboard.on('success', function (e) {
console.log('复制成功!')
console.log('操作文本内容:', e.text)
console.log('触发操作的DOM元素:', e.trigger)
e.clearSelection()
})
clipboard.on('error', function (e) {
console.log('复制失败')
console.error('触发操作的DOM元素:', e.trigger)
})
如果在触发器元素上定义 data-clipboard-text
属性,则不需要另一个元素来复制其内容。data-clipboard-text
属性值就是需要被复制的内容。
示例:
//触发器
var clipboard = new ClipboardJS('#copyBtn')
clipboard.on('success', function (e) {
console.log('复制成功!')
console.log('操作文本内容:', e.text)
console.log('触发操作的DOM元素:', e.trigger)
e.clearSelection()
})
clipboard.on('error', function (e) {
console.log('复制失败')
console.error('触发操作的DOM元素:', e.trigger)
})
事件监听
copy 事件
用户向剪贴板放入数据时,将触发 copy
事件。
示例:
document.addEventListener('copy', function (event) {
alert('触发复制事件')
//剪切板数据
console.log(event.clipboardData)
})
clipboardData 对象
上面示例中,事件对象的 clipboardData 属性包含了剪贴板数据。它是一个对象,有以下属性和方法。
setData( )
方法
Event.clipboardData.setData(type, data)
:在 cut
和 copy
事件中修改剪贴板数据,需要指定数据类型。
示例:
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dignissimos expedita temporibus facere mollitia nemo at voluptatibus dicta commodi neque iusto nesciunt earum suscipit deserunt delectus numquam cum nulla libero fugit.
var copyContent = document.querySelector('#copyContent');
copyContent.addEventListener('copy', (event) => {
const selection = document.getSelection();
//复制文本内容转大写
event.clipboardData.setData('text/plain', selection.toString().toUpperCase());
event.preventDefault();
});
getData( )
方法
Event.clipboardData.getData(type)
:在 paste
事件中获取剪贴板数据,需要指定数据类型。
示例:
document.addEventListener('paste', function (event) {
alert('触发粘贴事件')
//获取粘贴文本内容
var text = event.clipboardData.getData('text/plain');
console.log('粘贴内容:',text)
})
items
属性
Event.clipboardData.items
:一个类似数组的对象,包含了所有剪贴项,不过通常只有一个剪贴项。
cut 事件
cut
事件则是在用户进行剪切操作时触发,它的处理跟 copy
事件完全一样,也是从 Event.clipboardData
属性拿到剪切的数据。
示例:
document.addEventListener('cut', function () {
alert('触发剪切事件')
//剪切板数据
console.log(event.clipboardData)
})
paste 事件
用户使用剪贴板数据,进行粘贴操作时,会触发 paste
事件。
示例:
document.addEventListener('paste', async (e) => {
e.preventDefault();
//获取剪贴板里的文本数据
const text = await navigator.clipboard.readText();
console.log('粘贴文本: ', text);
});