复制按钮别再用 execCommand 了:用 Clipboard API 做一键复制
博客里的"复制代码"、文档里的"复制命令"、卡片上的"复制邀请链接",都是很常见的按钮。早年的标准写法是 document.execCommand(‘copy’),选中内容再执行。但这个 API 早被标记为废弃(deprecated),而且行为各浏览器不一致,有些环境下还会吞掉选中状态。现在浏览器有原生的 Clipboard API,navigator.clipboard.writeText 一行把文本写进剪贴板,干净可靠,新项目直接用它。
一、最小实现
async function copy(text) {
await navigator.clipboard.writeText(text)
tip.textContent = "已复制"
}
btn.addEventListener("click", () => copy(codeEl.textContent))
点击按钮,把要复制的文本交给 writeText,浏览器自己处理写入剪贴板。writeText 返回 Promise:成功 resolve 表示复制好了,失败 reject。比 execCommand 返回布尔值、还得先 select 再 copy 直观得多。codeEl.textContent 就是要复制的源码文本,从 DOM 里直接取。
二、给个反馈、失败兜底
复制不一定每次都成功(比如页面不在前台、权限被拒),所以加 try/catch,失败给提示让用户手动选,别悄悄没反应:
async function copy(text) {
try {
await navigator.clipboard.writeText(text)
showTip("已复制")
} catch (e) {
showTip("复制失败,请手动选择")
}
}
showTip 可以是个轻提示,几秒后消失。这样用户知道结果,体验完整。
三、复制富文本和图片
writeText 只管纯文本。要复制带格式的内容(比如一段 HTML)或图片,用更通用的 navigator.clipboard.write,配合 ClipboardItem:
const item = new ClipboardItem({
"text/html": new Blob([htmlString], { type: "text/html" }),
})
await navigator.clipboard.write([item])
ClipboardItem 的键是 MIME 类型,值是 Blob。纯文本场景用不到这个,writeText 足够。
四、几个要注意的点
第一,Clipboard API 要求"安全上下文":页面必须是 https 或 localhost,http 环境下调 writeText 会直接 reject,本地开发用 localhost 没事。第二,浏览器通常在"用户手势"里才允许复制(点击、按键),放在定时器或异步回调里可能被拦,所以复制逻辑放点击回调最稳。第三,读剪贴板用 readText,同样要安全上下文和权限,别随便读用户剪贴板,会被浏览器拦。第四,老浏览器不支持 clipboard 时降级回 execCommand,用 ‘clipboard’ in navigator 判断有没有原生 API,没有再走老路。第五,移动端部分浏览器对 Clipboard API 支持参差,真要做跨端的产品建议同时保留降级方案并测一遍。
五、小结
一键复制用 navigator.clipboard.writeText 最干净:一行把文本写进剪贴板,比废弃的 execCommand 可靠,也不用先 select。放在点击回调里调用、用 try/catch 兜底给反馈,留意只能 https/localhost 用。要复制富文本或图片换 ClipboardItem + write。老环境用 ‘clipboard’ in navigator 判断后降级回 execCommand,移动端记得测。
- 点赞
- 收藏
- 关注作者
评论(0)