fix(admin): copy buttons dead on HTTP origin — execCommand fallback

navigator.clipboard 仅安全上下文(HTTPS/localhost)可用,测试服务器经
http://IP:32005 访问时为 undefined,四处复制按钮(公开令牌/分享链接/
嵌入代码/重置密码)点击即抛 TypeError 且无提示。统一 utils/clipboard
copyText:API 优先、失败降级隐藏 textarea + execCommand。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-23 17:01:54 +08:00
parent cd8a3696e2
commit aaea76b0e3
6 changed files with 103 additions and 8 deletions
+34
View File
@@ -0,0 +1,34 @@
/**
* 复制文本到剪贴板(跨上下文兼容)。
*
* navigator.clipboard 仅**安全上下文**(HTTPS / localhost)可用——测试环境经
* http://IP:32005 访问时该 API 为 undefined,直接调用抛 TypeError(按钮
* 「点击无效」即此因)。降级路径:隐藏 textarea + select + execCommand('copy')
* (旧 API,HTTP 下可用);两条路径都失败返回 false 由调用方提示。
*/
export async function copyText(text: string): Promise<boolean> {
if (navigator.clipboard?.writeText) {
try {
await navigator.clipboard.writeText(text)
return true
} catch {
// 权限拒绝/焦点丢失等 → 落入 execCommand 降级
}
}
const textarea = document.createElement('textarea')
textarea.value = text
textarea.setAttribute('readonly', '')
// fixed + 屏外定位:不触发页面滚动,也避免移动端键盘弹出
textarea.style.position = 'fixed'
textarea.style.top = '-9999px'
document.body.appendChild(textarea)
textarea.select()
let ok = false
try {
ok = document.execCommand('copy')
} catch {
ok = false
}
document.body.removeChild(textarea)
return ok
}