feat(web): 添加剪贴板复制兼容 HTTP 环境

- 新增 useClipboard composable,支持 execCommand 备用方案
- 修复 HTTP 环境下复制按钮无响应问题
This commit is contained in:
mofeng-git
2025-12-31 20:31:42 +08:00
parent d0e2e13b35
commit 8be45155ac
2 changed files with 71 additions and 3 deletions

View File

@@ -0,0 +1,65 @@
import { ref } from 'vue'
export function useClipboard() {
const copied = ref(false)
// 检测是否支持原生 Clipboard API (需要安全上下文 + API 存在)
function canUseClipboardApi(): boolean {
return !!(
typeof navigator !== 'undefined' &&
navigator.clipboard &&
typeof navigator.clipboard.writeText === 'function' &&
window.isSecureContext
)
}
// Fallback: 使用 execCommand (兼容 HTTP 环境)
function fallbackCopy(text: string): boolean {
const textarea = document.createElement('textarea')
textarea.value = text
textarea.style.cssText = 'position:fixed;top:0;left:0;opacity:0;pointer-events:none'
document.body.appendChild(textarea)
textarea.focus()
textarea.select()
let success = false
try {
success = document.execCommand('copy')
} catch {
success = false
}
document.body.removeChild(textarea)
return success
}
async function copy(text: string): Promise<boolean> {
if (!text) return false
try {
if (canUseClipboardApi()) {
await navigator.clipboard.writeText(text)
} else {
if (!fallbackCopy(text)) {
return false
}
}
copied.value = true
setTimeout(() => (copied.value = false), 2000)
return true
} catch (e) {
// Clipboard API 失败时尝试 fallback
console.warn('Clipboard API failed, trying fallback:', e)
if (fallbackCopy(text)) {
copied.value = true
setTimeout(() => (copied.value = false), 2000)
return true
}
console.error('Copy failed:', e)
return false
}
}
return { copy, copied }
}