diff --git a/src/app/play/page.tsx b/src/app/play/page.tsx index 2f8d1b1..133ef53 100644 --- a/src/app/play/page.tsx +++ b/src/app/play/page.tsx @@ -2373,7 +2373,16 @@ function PlayPageClient() { icon: '', tooltip: '配置弹幕过滤规则', onClick() { - setShowDanmakuFilterSettings(true); + // 如果播放器处于全屏状态,先退出全屏 + if (artPlayerRef.current && artPlayerRef.current.fullscreen) { + artPlayerRef.current.fullscreen = false; + // 延迟一下再显示弹窗,确保全屏退出动画完成 + setTimeout(() => { + setShowDanmakuFilterSettings(true); + }, 300); + } else { + setShowDanmakuFilterSettings(true); + } return '打开设置'; }, }, diff --git a/src/components/DanmakuFilterSettings.tsx b/src/components/DanmakuFilterSettings.tsx index 7fe73d5..c18d158 100644 --- a/src/components/DanmakuFilterSettings.tsx +++ b/src/components/DanmakuFilterSettings.tsx @@ -24,6 +24,89 @@ export default function DanmakuFilterSettings({ const [newType, setNewType] = useState<'normal' | 'regex'>('normal'); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); + const [isVisible, setIsVisible] = useState(false); + const [isAnimating, setIsAnimating] = useState(false); + + // 控制动画状态 + useEffect(() => { + let animationId: number; + let timer: NodeJS.Timeout; + + if (isOpen) { + setIsVisible(true); + // 使用双重 requestAnimationFrame 确保DOM完全渲染 + animationId = requestAnimationFrame(() => { + animationId = requestAnimationFrame(() => { + setIsAnimating(true); + }); + }); + } else { + setIsAnimating(false); + // 等待动画完成后隐藏组件 + timer = setTimeout(() => { + setIsVisible(false); + }, 300); + } + + return () => { + if (animationId) { + cancelAnimationFrame(animationId); + } + if (timer) { + clearTimeout(timer); + } + }; + }, [isOpen]); + + // 阻止背景滚动 + useEffect(() => { + if (isVisible) { + // 保存当前滚动位置 + const scrollY = window.scrollY; + const scrollX = window.scrollX; + const body = document.body; + const html = document.documentElement; + + // 获取滚动条宽度 + const scrollBarWidth = window.innerWidth - html.clientWidth; + + // 保存原始样式 + const originalBodyStyle = { + position: body.style.position, + top: body.style.top, + left: body.style.left, + right: body.style.right, + width: body.style.width, + paddingRight: body.style.paddingRight, + overflow: body.style.overflow, + }; + + // 设置body样式来阻止滚动,但保持原位置 + body.style.position = 'fixed'; + body.style.top = `-${scrollY}px`; + body.style.left = `-${scrollX}px`; + body.style.right = '0'; + body.style.width = '100%'; + body.style.overflow = 'hidden'; + body.style.paddingRight = `${scrollBarWidth}px`; + + return () => { + // 恢复所有原始样式 + body.style.position = originalBodyStyle.position; + body.style.top = originalBodyStyle.top; + body.style.left = originalBodyStyle.left; + body.style.right = originalBodyStyle.right; + body.style.width = originalBodyStyle.width; + body.style.paddingRight = originalBodyStyle.paddingRight; + body.style.overflow = originalBodyStyle.overflow; + + // 使用 requestAnimationFrame 确保样式恢复后再滚动 + requestAnimationFrame(() => { + window.scrollTo(scrollX, scrollY); + }); + }; + } + }, [isVisible]); // 加载配置 useEffect(() => { @@ -114,111 +197,192 @@ export default function DanmakuFilterSettings({ })); }; - if (!isOpen) return null; + if (!isVisible) return null; return ( -
- * 普通模式:包含关键字即屏蔽 | 正则模式:支持正则表达式匹配 +
+ 💡 普通模式:包含关键字即屏蔽
+ 🔧 正则模式:支持正则表达式匹配
暂无屏蔽规则
+点击上方添加关键字
+