了解剪贴板 API,更智能地与用户交互📋
我们经常会遇到需要与用户剪贴板交互的情况。直到最近,浏览器还在使用document.execCommand
剪贴板交互。这听起来很棒,而且是(现在仍然是)在 Web 应用中广泛支持的复制、剪切和粘贴方式,但问题在于剪贴板访问是异步的,只能写入DOM
。
背景
剪贴板访问是异步的,这意味着用户体验会因为剪贴板传输而受到影响。粘贴时情况会更糟,因为在大多数情况下,你需要清理内容才能安全处理。
当涉及到权限时,情况会变得更糟,或者浏览器必须从文本中的链接复制信息,而页面必须等待网络请求,因此使用并不那么广泛。
剪贴板 API
这一切都令人沮丧,直到新的剪贴板 API诞生。这个 API 取代了基于document.execCommand
剪贴板的复制粘贴功能,它拥有定义明确的权限模型,并且不会阻塞页面。
此 API 是的属性window.navigator
,由以下属性和方法构成:
read()
readText()
write(data)
writeText(text)
addEventListener(event, handler)
removeEventListener(event, handler)
dispatchEvent(event)
要检测浏览器是否支持该功能,您可以执行以下操作:
if (navigator.clipboard) {
// yep, happy coding.
} else {
// oh no 😢. Use execCommand for now
}
除了这些优点之外,它还可以读取和写入系统剪贴板😍。剪贴板的访问需要权限 API 的支持,这意味着未经用户许可,这些操作均不被允许。
将文本复制到剪贴板
调用该方法可以将文本复制到剪贴板writeText
。此函数返回一个 Promise,该 Promise 将根据操作的执行方式被解决或拒绝。
navigator.clipboard.writeText('I am writing to clipboard 📋')
.then(() => {
console.log('Woohoo');
})
.catch(err => {
console.error('Oh no: ', err);
});
调用 catch 函数的原因之一是用户未授予权限或拒绝授予权限。
您可以使用async
函数和await
:
async function writeTextToClipboard() {
try {
await navigator.clipboard.writeText('I am writing to clipboard 📋');
console.log('Woohoo');
} catch (err) {
console.error('Oh no: ', err);
}
}
从剪贴板读取
要从剪贴板读取复制的文本,您可以使用该readText
方法并等待返回的承诺:
navigator.clipboard.readText()
.then(text => {
console.log('Pasted content: ', text);
})
.catch(err => {
console.error('Oh no: ', err);
});
还有async/await
:
async function getCopiedTextFromClioboard() {
try {
const text = await navigator.clipboard.readText();
console.log('Pasted content: ', text);
} catch (err) {
console.error('Oh no: ', err);
}
}
让我们通过演示来看一下。
请注意,您必须授予其运行权限。
处理糊剂
您可以连接到 (surprise)paste
事件,以便在document
文本复制到剪贴板并由用户代理触发粘贴操作时接收文本。如果您想修改接收到的数据,则需要阻止事件冒泡。
document.addEventListener('paste', async (e) => {
e.preventDefault(); // need to do something with the text
try {
let text = await navigator.clipboard.readText();
text = text.toUpperCase();
console.log('Pasted UPPERCASE text: ', text);
} catch (err) {
console.error('Oh no: ', err);
}
});
处理副本
与粘贴类似,您也可以处理复制事件:
document.addEventListener('copy', async (e) => {
e.preventDefault();
try {
for (const item of e.clipboardData.items) {
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob
})
]);
}
console.log('Image copied.');
} catch (err) {
console.error('Oh no: ', err);
}
});
权限
仅支持通过HTTPSnavigator.clipboard
传输的页面,并且剪贴板访问仅在允许的情况下才会受到限制,以防止进一步滥用。活动页面可以写入剪贴板,但读取剪贴板需要获得授权。
开发剪贴板 API 时引入了两个新权限:
clipboard-write
自动授予任何活动选项卡。- 必须
clipboard-read
提出请求。
const queryOpts = { name: 'clipboard-read' };
const permissionStatus = await navigator.permissions.query(queryOpts);
// Will be 'granted', 'denied' or 'prompt':
console.log(permissionStatus.state);
// Listen for changes to the permission state
permissionStatus.onchange = () => {
console.log(permissionStatus.state);
};
图片
我们并不经常使用文本,因此write()
引入了新的方法,允许我们将其他格式的数据写入剪贴板。此方法也是异步的,实际上,writeText
它是在后台调用的。
写入剪贴板
要将图像写入剪贴板,您需要将图像转换为Blob
。您可以使用 Canvas 元素调用 函数来实现toBlob()
。目前,您一次只能传递一张图片,Chrome 团队正在开发多张图片功能。
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext('2d');
var img = new Image();
img.setAttribute('crossorigin', 'anonymous');
img.onload = function() {
ctx.drawImage(img, 0, 0, 150, 150);
img.style.display = 'none';
canvas.toBlob(function(blob) {
navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob
})
]);
})
};
img.src = 'https://image-url';
从剪贴板读取图像
要读取图像,您需要使用该read()
方法,该方法读取数据并返回对象列表ClipboardItem
。您也可以使用for...of
它来处理这部分内容。async
每个返回的对象可能有不同的类型,因此最佳选择是调用getType()
它并进行相应的操作。在我们的例子中,对应的类型是Blob
。
const items = await navigator.clipboard.read();
for (const clipboardItem of items) {
for (const type of clipboardItem.types) {
if (type === "image/png") {
console.log(type);
const blob = await clipboardItem.getType(type);
}
}
}
您可以在此处看到完整的演示:
浏览器支持
截至撰写本文时,浏览器尚未支持此 API。Chrome 和 Firefox 完全支持 Clipboard API 和 ClipboardEvent API。
Edge 不支持它,但 Safari 已经支持它了。
概括
我们看到了使用这个出色的 API 操作剪贴板是多么简单和方便,以及用户体验将会有多好。
所以不用多说,祝你编码愉快💻。
鏂囩珷鏉ユ簮锛�https://dev.to/yashints/get-to-know-the-clipboard-api-be-smarter-with-user-interactions-2pp9