navigator.clipboard复制文字和图片的问题
最近要实现一个"将图片和文字复制到剪切板"的功能。接下来是我的实现的过程,在这个过程中踩到一些坑,记录一下。
将文字复制到剪切板
将一段文字复制到剪切板是很容易的一件事,W3C给我们提供了一些API。
- navigator.clipboard.writeText() 可以直接使用navigator.clipboard.writeText()来将一段文字复制到剪切板。
ts
const copyText = (
text: string,
): Promise<string> => {
return new Promise((resolve, reject) => {
// 剪切板API
const clipBoardApi = navigator.clipboard;
if (clipBoardApi) {
clipBoardApi.writeText(text)
.then(() => resolve('复制成功'))
.catch(reject);
} else {
reject('浏览器不支持navigator.clipboard方法');
}
});
}
- navigator.clipboard.write() 对于navigator.clipboard.writeText()来说,看到writeText就知道这个API明显只能够复制文字,和我们要实现的功能不太相符,所以我就使用了navigator.clipboard.write()方法。
ts
const copyText = (
text: string,
): Promise<string> => {
return new Promise((resolve, reject) => {
// 剪切板API
const clipBoardApi = navigator.clipboard;
if (clipBoardApi) {
const clipboardItemText = new Blob([text], {type: 'text/plain'});
const clipboardItem = new ClipboardItem({
'text/plain': clipboardItemText,
})
clipBoardApi.write([clipboardItem])
.then(() => resolve('复制成功'))
.catch(reject);
} else {
reject('浏览器不支持navigator.clipboard方法');
}
})
}
将图片复制到剪切板
更具上述使用navigator.clipboard.write()方法将文字复制到剪切板后,我们将代码改造一下就可以将图片复制到剪切板。
ts
const copyImage = (
url: string,
): Promise<string> => {
return new Promise(async (resolve, reject) => {
// 剪切板API
const clipBoardApi = navigator.clipboard;
if (clipBoardApi) {
const image = await fetch(url).then((response) => response.blob());
const clipboardItemImage = new Blob([image], {type: 'image/png'});
const clipboardItem = new ClipboardItem({
'image/png': clipboardItemImage,
})
clipBoardApi.write([clipboardItem])
.then(() => resolve('复制成功'))
.catch(reject);
} else {
reject('浏览器不支持navigator.clipboard方法');
}
})
}
将文字和图片复制
复制文字和图片到剪切板的代码都实现了,那么我们应该怎么样将其整合起来,将文字和图片一同复制到剪切板呢?看到ClipboardItem事例的参数是要求传递一个对象的时候,就大致有了思路,我们将文字和图片一起传入试一试。
ts
const copyImageText = (
url: string,
text: string,
): Promise<string> => {
return new Promise(async (resolve, reject) => {
// 剪切板API
const clipBoardApi = navigator.clipboard;
if (clipBoardApi) {
// 图片
const image = await fetch(url).then((response) => response.blob());
const clipboardItemImage = new Blob([image], {type: 'image/png'});
// 文字
const clipboardItemText = new Blob([text], {type: 'text/plain'});
const clipboardItem = new ClipboardItem({
'image/png': clipboardItemImage,
'text/plain': clipboardItemText,
})
clipBoardApi.write([clipboardItem])
.then(() => resolve('复制成功'))
.catch(reject);
} else {
reject('浏览器不支持navigator.clipboard方法');
}
})
}
但是上述代码测试下来发现只复制了文字,并没有复制图片。那么我们可以换种思路,navigator.clipboard.write()方法的参数传递是一个数组。
ts
const copyImageText2 = (
url: string,
text: string,
): Promise<string> => {
return new Promise(async (resolve, reject) => {
// 剪切板API
const clipBoardApi = navigator.clipboard;
if (clipBoardApi) {
// 图片
const image = await fetch(url).then((response) => response.blob());
const clipboardItemImage = new Blob([image], {type: 'image/png'});
// 文字
const clipboardItemText = new Blob([text], {type: 'text/plain'});
const handleClipboardItem = (key: string, value: Blob) => new ClipboardItem({
[key]: value,
})
clipBoardApi.write([
handleClipboardItem('image/png', clipboardItemImage),
handleClipboardItem('text/plain', clipboardItemText),
])
.then(() => resolve('复制成功'))
.catch(reject);
} else {
reject('浏览器不支持navigator.clipboard方法');
}
})
}
经过测试下来,发现报错了。
Uncaught (in promise) DOMException: Support for multiple ClipboardItems is not implemented.
查询文档中...
查找了相关的文档后,我发现无法在单次操作中同时复制多种类型的数据(例如文本和图片)到剪贴板。
最后实现方案
最后的实现方案就是将文字和图片都转成文字复制到剪切板,例如:123<img src=""/>
,然后复制到编译器后在编译器里进行处理,将<img src="" />
转换成对应的图片,因为处理的过程是基于ckEditor编译器的,过于复杂,所以具体过程就不放出来了。
总结
以上的代码和总结仅是本人的灼见,希望各位大佬们多批评。