From 2a0a5658b5c4b0f712cf04e4abafeda2d12e7a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Sun, 3 May 2026 20:43:40 +0800 Subject: [PATCH] =?UTF-8?q?refactor(clipboard):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=89=AA=E8=B4=B4=E6=9D=BF=E5=B7=A5=E5=85=B7=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E7=9B=B8=E5=85=B3=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 copyToClipboard 拆分为 copyTextToClipboard 和 copyImageToClipboard 移除 useClipboard hook 并将消息处理移至调用方 优化组件中的剪贴板操作错误处理逻辑 --- components/CopyButton.tsx | 16 +++++---- components/UrlToQrCodeSection.tsx | 27 ++++++--------- utils/clipboard.ts | 56 ++++++++++++++++--------------- 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/components/CopyButton.tsx b/components/CopyButton.tsx index b4236ca..6c178e4 100644 --- a/components/CopyButton.tsx +++ b/components/CopyButton.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { IconButton, Tooltip } from '@mui/material'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import CheckIcon from '@mui/icons-material/Check'; -import { copyToClipboard } from '@/utils/clipboard'; +import { copyTextToClipboard } from '@/utils/clipboard'; import type { SnackbarOptions } from '@/components/GlobalSnackbar'; /** @@ -45,11 +45,15 @@ export const CopyButton: React.FC = ({ const handleCopy = async () => { if (text) { - const success = await copyToClipboard(text, showMessage); - if (success) { - setCopied(true); - setTimeout(() => setCopied(false), 1500); - } + await copyTextToClipboard(text) + .then(() => { + showMessage?.('复制成功', { severity: 'success' }); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + }) + .catch(() => { + showMessage?.('复制失败', { severity: 'error' }); + }); } else { showMessage?.('无内容可复制', { severity: 'error' }); } diff --git a/components/UrlToQrCodeSection.tsx b/components/UrlToQrCodeSection.tsx index 8a3a392..4081a87 100644 --- a/components/UrlToQrCodeSection.tsx +++ b/components/UrlToQrCodeSection.tsx @@ -17,6 +17,7 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import QRious from 'qrious'; import { qrCodePageStyles } from '@/config/pageTheme'; import type { SnackbarOptions } from '@/components/GlobalSnackbar'; +import { copyImageToClipboard } from '@/utils/clipboard'; interface UrlToQrCodeSectionProps { expanded: boolean; @@ -80,27 +81,21 @@ const UrlToQrCodeSection = ({ link.href = qrCodeDataUrl; link.download = 'qrcode.png'; link.click(); - showMessage('二维码下载成功', { severity: 'success', autoHideDuration: 300 }); + showMessage('二维码下载成功', { severity: 'success' }); }; const copyQrCode = async () => { if (!qrCodeDataUrl) return; - try { - const response = await fetch(qrCodeDataUrl); - const blob = await response.blob(); - - await navigator.clipboard.write([ - new ClipboardItem({ - 'image/png': blob, - }), - ]); - - showMessage('二维码已复制到剪贴板', { severity: 'success', autoHideDuration: 1000 }); - } catch (error) { - console.error('复制二维码失败:', error); - showMessage('复制二维码失败,请重试', { severity: 'error', autoHideDuration: 300 }); - } + const response = await fetch(qrCodeDataUrl); + const blob = await response.blob(); + await copyImageToClipboard(blob) + .then(() => { + showMessage('二维码已复制到剪贴板', { severity: 'success' }); + }) + .catch(() => { + showMessage('复制二维码失败,请重试', { severity: 'error' }); + }); }; return ( diff --git a/utils/clipboard.ts b/utils/clipboard.ts index cd07b41..1c7eb7c 100644 --- a/utils/clipboard.ts +++ b/utils/clipboard.ts @@ -1,37 +1,39 @@ -import type { SnackbarOptions } from '@/components/GlobalSnackbar'; -import { useSnackbarState } from '@/components/GlobalSnackbar'; - /** * 复制文本到剪贴板 * @param text 要复制的文本 - * @param showMessage 显示消息的函数 * @returns Promise 是否复制成功 */ -export const copyToClipboard = async ( - text: string, - showMessage?: (message: string, options?: SnackbarOptions) => void, -): Promise => { - try { - await navigator.clipboard.writeText(text); - showMessage?.('已复制', { severity: 'success' }); - return true; - } catch (error) { - console.error('复制失败:', error); - showMessage?.('复制失败', { severity: 'error' }); - return false; - } +export const copyTextToClipboard = async (text: string): Promise => { + return new Promise((resolve, reject) => { + navigator.clipboard + .writeText(text) + .then(() => { + resolve(true); + }) + .catch(() => { + reject(false); + }); + }); }; /** - * 自定义 Hook: 用于处理剪贴板操作 - * @returns 包含复制函数和 snackbarProps 的对象 + * 复制图片到剪贴板 + * @param blob 要复制的图片 + * @returns Promise 是否复制成功 */ -export const useClipboard = () => { - const { snackbarProps, showMessage } = useSnackbarState({ autoHideDuration: 1500 }); - - const copy = async (text: string): Promise => { - return copyToClipboard(text, showMessage); - }; - - return { copy, snackbarProps }; +export const copyImageToClipboard = async (blob: Blob): Promise => { + return new Promise((resolve, reject) => { + navigator.clipboard + .write([ + new ClipboardItem({ + 'image/png': blob, + }), + ]) + .then(() => { + resolve(true); + }) + .catch(() => { + reject(false); + }); + }); };