35 lines
1.2 KiB
TypeScript
35 lines
1.2 KiB
TypeScript
|
|
/**
|
|||
|
|
* 复制文本到剪贴板(跨上下文兼容)。
|
|||
|
|
*
|
|||
|
|
* 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
|
|||
|
|
}
|