Clipboard API 读取剪贴板必须由用户手势触发,否则抛出 NotAllowedError;readText() 仅读纯文本且兼容性好,read() 支持多类型但 Safari 不支持;需先获 clipboard-read 权限,Firefox 还须显式申请。

Clipboard API 读取剪贴板需要用户手势触发
浏览器禁止页面在无用户交互(如点击、按键)时静默读取剪贴板,这是安全策略硬性限制。直接调用 navigator.clipboard.readText() 而不包裹在 click 或 keydown 回调里,会立即抛出 NotAllowedError 错误。
常见错误现象:Uncaught DOMException: Permission denied 或控制台提示 “readText() requires a user gesture”。
- 必须绑定到显式用户操作上,例如按钮
onclick、input的onpaste、或document.addEventListener('click', ...) - 不能放在
setTimeout、DOMContentLoaded、load等自动触发的钩子中 - 部分浏览器(如 Safari)对非 HTTPS 环境完全禁用
navigator.clipboard,本地file://协议也无效
readText() 和 read() 的适用场景与兼容性差异
readText() 只读纯文本,兼容性好(Chrome 66+、Firefox 63+、Edge 79+),是日常粘贴文本最稳妥的选择;read() 可读取图片、HTML、自定义类型等,但需手动解析 ClipboardItem,且 Safari 目前不支持 read()(仅支持 readText())。
如果只需要获取用户复制的字符串,优先用 readText();若需处理截图或富文本,得用 read() 并做好降级(比如 fallback 到 readText() + 提示“仅支持文字”)。
立即学习“前端免费学习笔记(深入)”;
-
readText()返回Promise<string>,无需解包 -
read()返回Promise<ClipboardItem[]>,需遍历每个item.types并调用item.getType('text/plain')或item.getType('image/png') - Firefox 对
read()的 MIME 类型支持较保守,例如可能不返回'text/html'即使复制的是网页内容
权限请求不是可选步骤,而是必要前置条件
Chrome 和 Edge 在首次调用 readText() 时会自动弹出权限提示(“此网站想要读取剪贴板”),但 Firefox 默认拒绝,必须提前申请:调用 navigator.permissions.query({name: 'clipboard-read'}) 并等待状态为 'granted' 才能继续。未获授权就调用会直接 reject。
- 不要假设权限已存在——即使用户点过“允许”,重启浏览器后状态可能重置
- 可在按钮点击后先检查权限:
if ((await navigator.permissions.query({name: 'clipboard-read'})).state === 'granted'),否则显式提示用户操作 - 避免在权限未决(
'prompt')时重复调用,可能导致提示被浏览器屏蔽
实际可用的最小可靠读取代码片段
下面这段代码能在点击按钮时读取文本并输出,覆盖主流错误处理:
<button id="pasteBtn">粘贴剪贴板文本</button>
<div id="output"></div>
<script>
document.getElementById('pasteBtn').addEventListener('click', async () => {
try {
const text = await navigator.clipboard.readText();
document.getElementById('output').textContent = text;
} catch (err) {
if (err.name === 'NotAllowedError') {
document.getElementById('output').textContent = '请先点击按钮再尝试';
} else if (err.name === 'NotFoundError') {
document.getElementById('output').textContent = '剪贴板为空或不包含文本';
} else {
document.getElementById('output').textContent = '读取失败:' + err.message;
}
}
});
</script>
注意:readText() 不会清空剪贴板,也不会触发系统粘贴行为,它只是“看一眼”。真正容易被忽略的是——很多开发者以为复制了图片或 HTML 就能用 readText() 拿到渲染后的文本,其实它只返回原始纯文本内容(比如复制一段带链接的段落,得到的是 URL 字符串而非可点击链接)。



















