refactor: 拆分 ShareCardModal(951 行 → 4 个模块)
- ShareCardModal.tsx (199 行): 模态框编排逻辑(图片生成、保存、分享) - RestaurantShareCard.tsx: 餐厅分享卡片纯展示组件 - BlindboxShareCard.tsx: 盲盒分享卡片纯展示组件 - shareImage.ts: 图片工具函数(toPng 封装、dataUrl 转换、下载)
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { toPng } from "html-to-image";
|
||||
|
||||
export async function loadImageAsDataUrl(src: string): Promise<string | null> {
|
||||
try {
|
||||
const img = new Image();
|
||||
img.crossOrigin = "anonymous";
|
||||
img.src = src;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
img.onload = () => resolve();
|
||||
img.onerror = () => reject();
|
||||
});
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = img.naturalWidth;
|
||||
canvas.height = img.naturalHeight;
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
return canvas.toDataURL("image/jpeg", 0.85);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateImage(el: HTMLElement): Promise<string> {
|
||||
return toPng(el, {
|
||||
pixelRatio: 2,
|
||||
quality: 0.95,
|
||||
cacheBust: true,
|
||||
skipAutoScale: true,
|
||||
filter: (node) => {
|
||||
if (node instanceof HTMLElement && node.dataset.shareExclude === "true") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function downloadDataUrl(dataUrl: string, filename: string) {
|
||||
const link = document.createElement("a");
|
||||
link.download = filename;
|
||||
link.href = dataUrl;
|
||||
link.click();
|
||||
}
|
||||
|
||||
export function dataUrlToFile(dataUrl: string, filename: string): File {
|
||||
const arr = dataUrl.split(",");
|
||||
const mime = arr[0].match(/:(.*?);/)?.[1] || "image/png";
|
||||
const bstr = atob(arr[1]);
|
||||
const u8 = new Uint8Array(bstr.length);
|
||||
for (let i = 0; i < bstr.length; i++) u8[i] = bstr.charCodeAt(i);
|
||||
return new File([u8], filename, { type: mime });
|
||||
}
|
||||
Reference in New Issue
Block a user