症状
错误“clipboard.writeText 的 NotAllowedError — 权限或手势”指向一个明确的失效模式。下面依次给出症状、定位该原因的检查命令、根本原因、修复方案,以及证明修复有效的验证步骤。
可观察到的症状包括:
- DOMException: 在 Clipboard 上执行 writeText 失败,文档未获得焦点
- 在 iframe 中复制失败并报 NotAllowedError
- 点击时复制可用,定时器中不可用
诊断
先在隔离环境中复现故障,再按顺序执行以下检查,逐步缩小范围。
步骤 1
navigator.clipboard.writeText('x').catch(e => console.log(e.name, e.message))
NotAllowedError 指出原因:丢失手势、文档未聚焦或缺少权限。
步骤 2
console.log(document.hasFocus(), await navigator.permissions.query({ name: 'clipboard-write' }))
聚焦与权限状态可判断是哪个条件不满足。
常见诱因(按出现频率排序):
- 在用户手势之外调用 writeText(如 await 之后)
- 文档未聚焦或运行在未聚焦的 iframe 中
- 跨源 iframe 缺少 clipboard-write 权限
根因
异步剪贴板 API 需要用户手势、聚焦的文档,以及(在 iframe 中)clipboard-write 权限。任一缺失都会使 writeText 以 NotAllowedError 拒绝。
修复
在手势处理器内、任何 await 之前同步调用 writeText,保持文档聚焦,在 iframe 的 allow 属性中申请 clipboard-write,并在失败时回退到基于选区的传统复制。
注意:静默失败会让用户误以为复制成功;应始终给出成功或失败反馈。
copyBtn.addEventListener('click', async () => {
try {
// inside the gesture: await the clipboard call immediately
await navigator.clipboard.writeText('text to copy');
showToast('Copied');
} catch (err) {
if (err.name === 'NotAllowedError') {
legacyCopy('text to copy'); // selection + execCommand fallback
} else {
console.error(err);
}
}
});
<!-- iframe must be permitted to use the clipboard -->
<iframe src="..." allow="clipboard-write"></iframe>
验证
点击复制并确认文本进入剪贴板;验证 iframe 的 allow 属性允许 clipboard-write。
修复后补充一条回归测试,复现原始症状,防止问题再次出现。
这类故障通常是环境问题而非纯逻辑错误,因此在缺陷记录中应写明完整命令、环境变量与工作目录。请用最小的脚本复现,待最小用例清楚后再扩大范围。为这类故障准备一份简短的排查清单,能显著减少下次排障时间。