From 95c33f6604ecfde1ce0e7a6c2c17c7a0b7b590a0 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 20 Aug 2026 23:49:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20Canvas=20=E5=86=85=E9=83=A8=E5=88=86?= =?UTF-8?q?=E8=BE=A8=E7=8E=87=E4=B8=8D=E5=8C=B9=E9=85=8D=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=94=BB=E9=9D=A2=E5=8F=98=E5=BD=A2=20=E2=80=94=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20ResizeObserver=20=E6=9C=AA=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:ResizeObserver useEffect 依赖数组为空 [],组件挂载时 canPlay=false 导致 canvas 未渲染、canvasRef 为 null,effect 直接 return 后永远不会重新执行, canvas 内部分辨率停留在浏览器默认值 300×150(横屏 2:1),而 CSS 显示为竖屏容器。 修复: - useEffect 依赖改为 [useWebCodecs, canPlay],canPlay=true 时 canvas 已渲染, effect 重新执行并正确创建 ResizeObserver - 创建 ResizeObserver 前立即通过 getBoundingClientRect 设置 canvas 初始像素分辨率, 避免首帧使用默认 300×150 导致变形 - computeDrawRect 已正确基于 videoDimRef 做 letterbox 居中绘制,无需修改 --- .../generate/components/FrontendPreviewPlayer.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx b/apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx index 9378caa1b..92d4b16df 100644 --- a/apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx +++ b/apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx @@ -250,9 +250,17 @@ const FrontendPreviewPlayer: React.FC = ({ // ── Canvas ResizeObserver ── const canvasContainerRef = useRef(null) useEffect(() => { + if (!useWebCodecs || !canPlay) return const container = canvasContainerRef.current const canvas = canvasRef.current if (!container || !canvas) return + // 立即设置一次 canvas 像素分辨率,避免默认 300×150 导致首帧变形 + const initRect = container.getBoundingClientRect() + if (initRect.width > 0 && initRect.height > 0) { + const dpr = window.devicePixelRatio || 1 + canvas.width = initRect.width * dpr + canvas.height = initRect.height * dpr + } const ro = new ResizeObserver((entries) => { for (const entry of entries) { const { width, height } = entry.contentRect @@ -264,7 +272,7 @@ const FrontendPreviewPlayer: React.FC = ({ }) ro.observe(container) return () => ro.disconnect() - }, []) + }, [useWebCodecs, canPlay]) // ── 未就绪 ── if (!ready || !assets.length) {