mirror of
https://github.com/wangdoc/webapi-tutorial.git
synced 2025-12-24 10:44:17 +08:00
docs: add Clipboard API
This commit is contained in:
195
docs/clipboard.md
Normal file
195
docs/clipboard.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
# Clipboard API 教程
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
|
||||||
|
Clipboard API 用于读写浏览器的剪贴板,取代传统的`document.execCommand()`方法。这个 API 的最大特点,就是所有操作都是异步的,返回 Promise 对象。
|
||||||
|
|
||||||
|
通过`navigator.clipboard`属性,可以获取这个 API。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const clipboardObj = navigator.clipboard;
|
||||||
|
```
|
||||||
|
|
||||||
|
这个 API 有明确的安全限制。Chrome 浏览器规定,只有 HTTPS 协议的页面才能使用这个 API,不过开发环境(`localhost`)可以用非加密协议。另外,只有当前页才允许脚本访问剪贴板。
|
||||||
|
|
||||||
|
注意,由于 Chrome 仅在页面为当前页时才允许剪贴板访问,因此如果直接把代码粘贴到开发者工具中,可能会报错,因为这时开发者工具的窗口本身就是当前页。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
(async () => {
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
console.log(text);
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
上面的代码放到开发者工具里面运行会报错,因为代码运行的时候,开发者工具窗口是当前页,这个页面不存在`document`相关的一系列对象。一个解决方法就是使用`setTimeout()`延迟剪贴板的访问,在调用函数之前快速点击浏览器的页面窗口,将其变成当前页。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
setTimeout(async () => {
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
console.log(text);
|
||||||
|
}, 2000);
|
||||||
|
```
|
||||||
|
|
||||||
|
Clipboard API 还有权限问题。由于用户可能把敏感数据(比如密码)放在剪贴板,所以这个 API 的调用需要明确获得用户的许可。它的权限许可用了 Permissions API,其中跟剪贴板相关的有两个权限:`clipboard-write`和`clipboard-read`。Chrome 浏览器规定,当页面是当前页时,`clipboard-write`权限会自动授予脚本,`clipboard-read`权限则必须用户明确同意给予。也就是说,在当前页中,脚本调用 Clipboard API 时,可以在不请求权限的情况下写入剪贴板,但是读取剪贴板时,浏览器会弹出一个对话框,询问用户是否给予脚本读取剪贴板的权限。
|
||||||
|
|
||||||
|
## 方法
|
||||||
|
|
||||||
|
Clipboard 对象提供了四个方法,用来读写剪贴板。它们都是异步方法,返回 Promise 对象。
|
||||||
|
|
||||||
|
### Clipboard.read()
|
||||||
|
|
||||||
|
`Clipboard.read()`方法拷贝一份剪贴板数据。该方法获取的数据,可以是文本数据,也可以是二进制数据(比如图片)。
|
||||||
|
|
||||||
|
该方法返回一个 Promise 对象。一旦该对象的状态变为 resolved,就可以获得一个包含剪贴板内容的 DataTransfer 对象。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const promise = navigator.clipboard.read();
|
||||||
|
```
|
||||||
|
|
||||||
|
读取剪贴板之前,必须先获取`clipboard-read`许可。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function getClipboardContents() {
|
||||||
|
try {
|
||||||
|
const clipboardItems = await navigator.clipboard.read();
|
||||||
|
for (const clipboardItem of clipboardItems) {
|
||||||
|
for (const type of clipboardItem.types) {
|
||||||
|
const blob = await clipboardItem.getType(type);
|
||||||
|
console.log(URL.createObjectURL(blob));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.name, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Clipboard.readText()
|
||||||
|
|
||||||
|
`Clipboard.readText()`拷贝一份剪贴板的文本数据。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.body.addEventListener(
|
||||||
|
"click",
|
||||||
|
async (e) => {
|
||||||
|
const text = await navigator.clipboard.readText()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function getClipboardContents() {
|
||||||
|
try {
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
console.log('Pasted content: ', text);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to read clipboard contents: ', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Clipboard.write()
|
||||||
|
|
||||||
|
`Clipboard.write()`用于将任意数据写入剪贴板。
|
||||||
|
|
||||||
|
该方法需要需要获取`clipboard-write`权限许可。当页面在活动选项卡时,可以被自动许可。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
const imgURL = '/images/generic/file.png';
|
||||||
|
const data = await fetch(imgURL);
|
||||||
|
const blob = await data.blob();
|
||||||
|
await navigator.clipboard.write([
|
||||||
|
new ClipboardItem({
|
||||||
|
[blob.type]: blob
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
console.log('Image copied.');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.name, err.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
下面的例子是同时复制多种格式的数据,一种是文本数据,一种是二进制数据,供不同的场合粘贴使用。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function copy() {
|
||||||
|
const image = await fetch('kitten.png');
|
||||||
|
const text = new Blob(['Cute sleeping kitten'], {type: 'text/plain'});
|
||||||
|
const item = new ClipboardItem({
|
||||||
|
'text/plain': text,
|
||||||
|
'image/png': image
|
||||||
|
});
|
||||||
|
await navigator.clipboard.write([item]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Clipboard.writeText()
|
||||||
|
|
||||||
|
`Clipboard.writeText()`用于将文本内容写入剪贴板。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function copyPageUrl() {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(location.href);
|
||||||
|
console.log('Page URL copied to clipboard');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy: ', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
下面是另一个例子。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.body.addEventListener(
|
||||||
|
"click",
|
||||||
|
async (e) => {
|
||||||
|
await navigator.clipboard.writeText("Yo")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## copy 事件
|
||||||
|
|
||||||
|
复试剪贴板数据时,将触发`copy`事件。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.addEventListener('copy', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
let clipboardItems = [];
|
||||||
|
for (const item of e.clipboardData.items) {
|
||||||
|
if (!item.type.startsWith('image/')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
clipboardItems.push(
|
||||||
|
new ClipboardItem({
|
||||||
|
[item.type]: item,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
await navigator.clipboard.write(clipboardItems);
|
||||||
|
console.log('Image copied.');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.name, err.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## paste 事件
|
||||||
|
|
||||||
|
粘贴剪贴板数据时,可以利用`paste`事件。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.addEventListener('paste', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
console.log('Pasted text: ', text);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 参考链接
|
||||||
|
|
||||||
|
- [Unblocking clipboard access](https://web.dev/async-clipboard/)
|
||||||
|
|
||||||
Reference in New Issue
Block a user