refactor(clipboard): 重构剪贴板工具函数并优化相关组件

将 copyToClipboard 拆分为 copyTextToClipboard 和 copyImageToClipboard
移除 useClipboard hook 并将消息处理移至调用方
优化组件中的剪贴板操作错误处理逻辑
This commit is contained in:
雨霖铃
2026-05-03 20:43:40 +08:00
parent 57ea4d9858
commit 2a0a5658b5
3 changed files with 50 additions and 49 deletions
+8 -4
View File
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { IconButton, Tooltip } from '@mui/material'; import { IconButton, Tooltip } from '@mui/material';
import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import CheckIcon from '@mui/icons-material/Check'; import CheckIcon from '@mui/icons-material/Check';
import { copyToClipboard } from '@/utils/clipboard'; import { copyTextToClipboard } from '@/utils/clipboard';
import type { SnackbarOptions } from '@/components/GlobalSnackbar'; import type { SnackbarOptions } from '@/components/GlobalSnackbar';
/** /**
@@ -45,11 +45,15 @@ export const CopyButton: React.FC<CopyButtonProps> = ({
const handleCopy = async () => { const handleCopy = async () => {
if (text) { if (text) {
const success = await copyToClipboard(text, showMessage); await copyTextToClipboard(text)
if (success) { .then(() => {
showMessage?.('复制成功', { severity: 'success' });
setCopied(true); setCopied(true);
setTimeout(() => setCopied(false), 1500); setTimeout(() => setCopied(false), 1500);
} })
.catch(() => {
showMessage?.('复制失败', { severity: 'error' });
});
} else { } else {
showMessage?.('无内容可复制', { severity: 'error' }); showMessage?.('无内容可复制', { severity: 'error' });
} }
+9 -14
View File
@@ -17,6 +17,7 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import QRious from 'qrious'; import QRious from 'qrious';
import { qrCodePageStyles } from '@/config/pageTheme'; import { qrCodePageStyles } from '@/config/pageTheme';
import type { SnackbarOptions } from '@/components/GlobalSnackbar'; import type { SnackbarOptions } from '@/components/GlobalSnackbar';
import { copyImageToClipboard } from '@/utils/clipboard';
interface UrlToQrCodeSectionProps { interface UrlToQrCodeSectionProps {
expanded: boolean; expanded: boolean;
@@ -80,27 +81,21 @@ const UrlToQrCodeSection = ({
link.href = qrCodeDataUrl; link.href = qrCodeDataUrl;
link.download = 'qrcode.png'; link.download = 'qrcode.png';
link.click(); link.click();
showMessage('二维码下载成功', { severity: 'success', autoHideDuration: 300 }); showMessage('二维码下载成功', { severity: 'success' });
}; };
const copyQrCode = async () => { const copyQrCode = async () => {
if (!qrCodeDataUrl) return; if (!qrCodeDataUrl) return;
try {
const response = await fetch(qrCodeDataUrl); const response = await fetch(qrCodeDataUrl);
const blob = await response.blob(); const blob = await response.blob();
await copyImageToClipboard(blob)
await navigator.clipboard.write([ .then(() => {
new ClipboardItem({ showMessage('二维码已复制到剪贴板', { severity: 'success' });
'image/png': blob, })
}), .catch(() => {
]); showMessage('复制二维码失败,请重试', { severity: 'error' });
});
showMessage('二维码已复制到剪贴板', { severity: 'success', autoHideDuration: 1000 });
} catch (error) {
console.error('复制二维码失败:', error);
showMessage('复制二维码失败,请重试', { severity: 'error', autoHideDuration: 300 });
}
}; };
return ( return (
+29 -27
View File
@@ -1,37 +1,39 @@
import type { SnackbarOptions } from '@/components/GlobalSnackbar';
import { useSnackbarState } from '@/components/GlobalSnackbar';
/** /**
* 复制文本到剪贴板 * 复制文本到剪贴板
* @param text 要复制的文本 * @param text 要复制的文本
* @param showMessage 显示消息的函数
* @returns Promise<boolean> 是否复制成功 * @returns Promise<boolean> 是否复制成功
*/ */
export const copyToClipboard = async ( export const copyTextToClipboard = async (text: string): Promise<boolean> => {
text: string, return new Promise((resolve, reject) => {
showMessage?: (message: string, options?: SnackbarOptions) => void, navigator.clipboard
): Promise<boolean> => { .writeText(text)
try { .then(() => {
await navigator.clipboard.writeText(text); resolve(true);
showMessage?.('已复制', { severity: 'success' }); })
return true; .catch(() => {
} catch (error) { reject(false);
console.error('复制失败:', error); });
showMessage?.('复制失败', { severity: 'error' }); });
return false;
}
}; };
/** /**
* 自定义 Hook: 用于处理剪贴板操作 * 复制图片到剪贴板
* @returns 包含复制函数和 snackbarProps 的对象 * @param blob 要复制的图片
* @returns Promise<boolean> 是否复制成功
*/ */
export const useClipboard = () => { export const copyImageToClipboard = async (blob: Blob): Promise<boolean> => {
const { snackbarProps, showMessage } = useSnackbarState({ autoHideDuration: 1500 }); return new Promise((resolve, reject) => {
navigator.clipboard
const copy = async (text: string): Promise<boolean> => { .write([
return copyToClipboard(text, showMessage); new ClipboardItem({
}; 'image/png': blob,
}),
return { copy, snackbarProps }; ])
.then(() => {
resolve(true);
})
.catch(() => {
reject(false);
});
});
}; };