From 48f94fbc68bf7cbb418fad8319fde3c8787bf9b9 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 6 Aug 2026 10:32:40 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AD=97=E4=BD=93=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E6=97=B6=E9=87=8D=E7=BD=AEfontLoaded=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=B9=B6=E9=87=8D=E6=96=B0=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - titleSettings变更时setFontLoaded(false)重置 - 使用document.fonts.check(fontSpec)精确检测目标字体 - 字体未加载时用document.fonts.load等待后重绘 - 移除setTimeout魔法数字,改用requestAnimationFrame --- .../generate/components/PreviewVideoPanel.tsx | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/apps/web/src/pages/generate/components/PreviewVideoPanel.tsx b/apps/web/src/pages/generate/components/PreviewVideoPanel.tsx index caebb57b9..ea74a1621 100644 --- a/apps/web/src/pages/generate/components/PreviewVideoPanel.tsx +++ b/apps/web/src/pages/generate/components/PreviewVideoPanel.tsx @@ -267,21 +267,50 @@ export const PreviewVideoPanel: React.FC = ({ return () => observer.disconnect() }, [showTitlePreview, hasPreview, isError, drawNoVideoTitle]) - // 字体加载完成后重绘(Canvas measureText 依赖字体已加载) + // 字体加载检测:当字体变更时重新检测,确保 measureText 使用正确字体计算 useEffect(() => { - if (!showTitlePreview) return + if (!showTitlePreview || !titleSettings) { + setFontLoaded(false) + return + } let cancelled = false - document.fonts.ready.then(() => { - if (cancelled) return - // 短暂延迟确保字体完全可用 - setTimeout(() => { - if (!cancelled) setFontLoaded(true) - }, 50) - }) + setFontLoaded(false) // 字体变更时重置,防止使用 fallback 字体绘制 + + const fontWeight = titleSettings.bold ? "bold" : "" + const fontStyle = titleSettings.italic ? "italic" : "" + const fontSpec = + `${fontStyle} ${fontWeight} ${titleSettings.size}px "${titleSettings.font}"`.trim() + + // 优先用 document.fonts.check 精确检测目标字体 + if (document.fonts.check(fontSpec)) { + setFontLoaded(true) + return + } + + // 字体尚未加载,等待后重试 + document.fonts + .load(fontSpec) + .then(() => { + if (!cancelled) { + // requestAnimationFrame 确保在下一帧绘制前字体已可用 + requestAnimationFrame(() => { + if (!cancelled) setFontLoaded(true) + }) + } + }) + .catch(() => { + // load 失败时回退到 fonts.ready + if (!cancelled) { + document.fonts.ready.then(() => { + if (!cancelled) setFontLoaded(true) + }) + } + }) + return () => { cancelled = true } - }, [showTitlePreview]) + }, [showTitlePreview, titleSettings]) // video 加载完成后重绘 const handleVideoLoaded = useCallback(() => {