在工作中会遇到一些需求场景,例如粘贴图片后自动上传,富文本编辑器内粘贴文本与图片,这些都与 Clipboard API 相关,在此讲解一下最新的 Clipboard API 的内容。
本文的示例页面: Clipboard API demo 代码地址: Github
Clipboard API 的能力
Clipboard API 是干什么的呢?
借用 MDN 的介绍,总结来说就是两点:
- 让我们能够读取和写入剪切板的内容;
- 让我们能够监听复制、剪切和粘贴事件(即 copy、cut、paste ),并做一些额外处理。
Clipboard API 的组成
Clipboard API 由 Clipboard
、ClipboardItem
和 Clipboard Event
几个内容组成。
Clipboard
接口是对剪切板的抽象,提供了读取剪切板、写入剪切板的方法。我们通过Clipboard
的实例,就能操作系统剪切板,比如任意用户剪切板的内容。ClipboardItem
接口是对剪切板里的内容的抽象,比如我们选中网页上的一段文字,并右击选择复制,这样复制的内容就作为一个ClipboardItem
存在。后面会详细介绍。Clipboard Event
顾名思义,就是复制粘贴这些事件。通过监听 copy、cut、paste 这几个事件,我们可以在用户进行复制、粘贴时做一些额外的处理操作。比如,你复制我博客的内容时,我可以更改你复制的内容,加上一段版权信息?。
操作剪切板
虽然 Web 提供了 Clipboard
接口,但是我们不会去手动创建它,而是通过 navigator.clipboard
属性来操作剪切板。
navigator.clipboard
有四个方法:
readText
: 用来读取剪切板的文本内容read
: 我们可能复制一些非文本内容,如图片,文件等,read
方法提供了这个功能writeText
: 向剪切板写入文本write
: 向剪切板写入多种格式的内容,如写入一个图片或者带格式的 HTML 片段
上面四个方法返回的都是 Promise
, 区别在于读取内容的方法会把读取到的内容在 Promise
中返回,一段简单示例如下:
navigator.clipboard.readText().then((text) => { console.log(text) });
为什么返回的都是 Promise
呢?
因为操作剪切板很容易泄露用户隐私,还会造成一些安全问题,所以调用操作剪切板的方法时会先向用户请求权限,用户同意之后才会往下进行,这个时候 promise 状态会变为 resolved
,如果用户拒绝,则该 promise 状态变为 rejected
。
下面进行详细的示例讲解,可以点击 Demo 页面实际操作,理解会更加深入。
读取文本
读取文本很简单,只需要调用 readText
方法即可把剪切板内的文本读取出来:
navigator.clipboard.readText().then((text) => { console.log(text) });
读取MIME格式的内容
通过 read()
方法可以读取文本、图片、文件等内容,目前 read()
方法只有最新的 Chrome 实现了读取 image/png
格式的功能。通过 read()
方法读取到的内容是一个 ClipboardItems
数组。比如我们在网页上找一个图片,右键点击复制,然后把读取到的数据打印出来:
ClipboardItem
有以下属性和方法:
types
属性: 包含了刚刚复制的内容的格式列表,getType()
方法: 这个方法传入的参数是表示类型的字符串,如text/html
, 返回一个 Promise ,通过该 Promise 我们可以获取该格式对应内容的 Blob 类型。
上述图片中可以看到 types
有两个值:["text/html", "image/png"]
, 因为我们虽然复制的是图片,但是实际上复制了两个格式的内容:
text/html
: 这是带有 html 格式的文本,例如我复制了 Vue 的logo,实际内容如下:<meta charset="utf-8"><img src="https://cn.vuejs.org/images/logo.png" >
image/png
: 这是我们复制的图片内容。
调用一下 types
属性:
navigator.clipboard.read().then(clipboardItems => {
console.log(clipboardItems[0].types)
})
// ["text/html", "image/png"]
通过 Blob.text()
方法可以得到 Blob 内容对应的文本格式,查看一下 text/html
对应的内容:
navigator.clipboard.read().then(async clipboardItems => {
const blob = await clipboardItems[0].getType('text/html')
const text = await blob.text()
console.log(text)
})
// <meta charset="utf-8"><img src="https://cn.vuejs.org/images/logo.png" >
我们可以把剪切板的所有内容读取并展示出来:
- 对于文本,直接显示其内容
- 对于图片,则读取图片的二进制数据并渲染出来
示例代码如下:
navigator.clipboard.read().then(async clipboardItems => {
const promises = clipboardItems.map(async (item: ClipboardItem) => {
// 获取所有的 types 并获取对应的内容
const promises = item.types.map(async type => {
const typeData = await item.getType(type)
let data = ''
if (/text/.test(type)) {
data = await typeData?.text?.()
} else if (/image/.test(type)) {
// 将图片内容读取为 DataUrl
data = URL.createObjectURL(typeData)
}
return { type, data, }
})
const typeList = await Promise.all(promises)
return typeList
})
clipboardData.clipboardItemList = await Promise.all(promises)
console.log(clipboardData.clipboardItemList)
})
本段代码的实际效果可以从这里看到。复制一个图片,点击 "获取剪切板MIME类型的内容" 按钮,下方会展示剪切板上所有类型的内容。
向 Clipboard 写入内容
向 Clipboard 中写入文本和读取文本内容一样简单,使用 writeText()
即可,不再多说:
navigator.clipboard.writeText('这是往剪切板中写入的文本内容').then(() => {
alert('写入成功, 可以往文本框里复制内容')
})
我们也可以通过 Clipboard.write()
方法向剪切板中写入图片等内容。write()
方法的参数是一个 ClipboardItem
的数组。
上文介绍了 ClipboardItem
的属性和方法,下面介绍一下如何创建 ClipboardItem
实例。
创建 ClipboardItem
实例需要传入一个对象,对象中的 key 代表内容的类型,如 text/html
,对象的 value 是 Blob 类型的数据,例如,创建一个 HTML 片段:
const clipboardItem = new ClipboardItem({
'text/html': new Blob([ '<span style="color: #9cdcfe;">这是文案的html格式</span>' ], { type: 'text/html' }),
})
// 然后将其写入剪切板
navigator.clipboard.write([ clipboardItem ]).then(() => {
alert('写入成功')
})
此时如果获取剪切板的内容或者去支持富文本的输入框(比如微信)中粘贴,就能看到我们写入的内容。
响应 Clipboard 事件
Clipboard API 还能让我们响应复制、粘贴等事件。只需要给特定的元素增加 copy
cut
或 paste
事件监听函数,即可监听到这些事件。
我们监听这些事件一般会有两种处理:
- 在
copy
和cut
事件发生时改变存储到剪切板的内容,例如你在 CSDN 博客上复制一段话,然后粘贴到自己的博客时,会发现粘贴的内容多了一段版权信息,就是利用这些事件做的。 - 在
paste
事件发生时读取剪切板的内容,例如富文本编辑器实现粘贴图片后自动上传服务器。
在这些时间处理函数中,我们可以直接通过上述介绍的读取和写入方法操作 navigator.clipboard
:
document.querySelector('.input').addEventListener('copy', () => {
navigator.clipboard.read().then(clipboardItems => {
console.log(clipboardItems[0].types)
})
});
不过由于目前浏览器对 navigator.clipboard
的功能支持不是很完善,所以可以利用旧的 API 来实现对剪切板的读取与写入。
在触发 copy
cut
或 paste
事件时,事件对象上的 clipboardData
属性可以让我们读取或写入剪切板。
拦截 paste
事件
event.clipboardData
是一个 DataTransfer
对象, 提供了两个方法:
getData(format)
: 读取剪切板的内容,需要传入要读取的内容类型,如getData('text/html')
;setData(format, data)
方法来设置剪切板的内容,参数分别为表示类型的字符串和该类型对应的数据内容。
例如,我们在一个输入框中拦截粘贴操作,并更改粘贴行为:
const onPaste = e => {
//
const text = e.clipboardData.getData('text/plain')
e.target.value = '这是代码手动更改后的内容:\n\n' + text
e.preventDefault()
}
document.querySelector('.input').addEventListener('paste', onPaste)
clipboardData
有一个 items
属性,是 DataTransferItem的列表,从中我们可以获取剪切板中的所有内容。利用 items
我们将在粘贴时获取剪切板中的图片,并进行如上传等处理:
const onPaste = e => {
// 类数组对象
const items = [ ...e.clipboardData.items ]
let file;
items.forEach((item, index) => {
const { type } = item
if (type === 'image/png') {
// 利用 DataTransferItem 的 getAsFile 获取文件数据
file = URL.createObjectURL(item.getAsFile())
const formData = new FormData()
formData.append('file', file);
// 在这里进行上传
}
})
e.preventDefault()
}
document.querySelector('.input').addEventListener('paste', onPaste)
拦截 copy
、cut
事件
拦截 copy
、cut
事件,我们可以更改用户复制的内容:
const onCopy = e => {
console.log(e.clipboardData)
const selection = document.getSelection()
e.clipboardData.setData('text/plain', `你复制的内容已经被我更改了!${selection}`)
e.preventDefault()
}
document.querySelector('.input').addEventListener('copy', onCopy)
上述示例均可以在 Demo 页面查看。
总结
Clipboard API 所覆盖的知识不多,总的来说有以下三方面:
Clipboard
接口提供了操作剪切板的一些方法,主要应牢记以下几个方面:- 通过
navigator.clipboard
来操作剪切板; - 有四个方法(目前)可以使用:
read()
和readText()
,write()
和writeText()
,都返回一个 Promise - 使用
navigator.clipboard
会向用户请求授权。
- 通过
ClipboardItem
接口代表剪切板里的一个内容,比如我们右击图片点击复制,此时剪切板里会增加一项ClipboardItem
,保存着两种格式的内容:text/html
和image/png
。- 使用
Clipboard.read()
方法读取到的数据是ClipboardItem
组成的数组; - 每个
ClipboardItem
有一个types
属性,包含了其保存的所有内容的类型,如:['text/html', 'image/png']
- 每个
ClipboardItem
有一个getType
方法,其返回 Promise, 传入上一条的类型即可获取对应的内容,如:getType('text/html')
- 使用
Clipboard.write()
方法向剪切板写入数据时,需要创建ClipboardItem
实例:const item = new ClipboardItem({ 'text/html': new Blob([ '<span style="color: #9cdcfe;">html</span>' ]) })
- 使用
- Clipboard Event 可以让我们拦截复制、剪切和粘贴事件,并改变默认行为:
- 监听的事件有: copy、cut、paste
- 通过
event.clipboardData.getData(format)
可以获取剪切板内容; - 通过
event.clipboardData.getData(format, data)
可以更改 copy 和 cut 时写入剪切板的内容; - 通过
event.clipboardData.items
能获取到所有剪切板的内容,实现粘贴自动上传等功能
以上就是关于 Clipboard API 的全部内容了,希望能帮到大家~
欢迎关注我,后续会继续写更多优质博客与大家分享。同时,有任何问题,欢迎一起讨论~
附原文链接
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!