From f85d1732c4889d6279b316bc6e219129d40a8b6a Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 29 Dec 2025 22:19:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=BE=E7=89=87=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=99=A8=E5=BC=B9=E7=AA=97=E5=AE=9A=E4=BD=8D=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=9A=E4=BD=BF=E7=94=A8React=20Portal=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E5=88=B0document.body?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用createPortal将弹窗渲染到document.body,避免受父元素定位影响 - 添加客户端渲染检查,确保SSR兼容性 - 解决从顶部导航栏打开时弹窗被遮挡的问题 --- components/image-annotator.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/components/image-annotator.tsx b/components/image-annotator.tsx index 5aa747d..e417aa2 100644 --- a/components/image-annotator.tsx +++ b/components/image-annotator.tsx @@ -1,6 +1,7 @@ "use client"; import React, { useRef, useState, useEffect, useCallback } from "react"; +import { createPortal } from "react-dom"; import { X, Pencil, Circle, ArrowRight, Type, Check, Undo, Trash2, Scissors, Sparkles, Download, Expand } from "lucide-react"; import { Button } from "./ui/button"; import { toast } from "sonner"; @@ -64,6 +65,12 @@ export function ImageAnnotator({ imageUrl, onConfirm, onCancel }: ImageAnnotator const [processedImageUrl, setProcessedImageUrl] = useState(null); const [processedImageBase64, setProcessedImageBase64] = useState(null); const [processType, setProcessType] = useState<"rmbg" | "enhance" | "extend" | null>(null); + const [mounted, setMounted] = useState(false); + + // 确保在客户端渲染 + useEffect(() => { + setMounted(true); + }, []); // 加载图片 useEffect(() => { @@ -563,7 +570,8 @@ export function ImageAnnotator({ imageUrl, onConfirm, onCancel }: ImageAnnotator onConfirm(dataUrl); }; - return ( + // 弹窗内容 + const modalContent = (
); + + // 使用 Portal 渲染到 document.body,避免受父元素定位影响 + if (!mounted) { + return null; + } + + return createPortal(modalContent, document.body); }