React仿PPT/Canva项目:修改内容时Fullscreen API自动退出问题求助
解决React幻灯片项目全屏预览因重渲染退出的问题
问题根源
浏览器的Fullscreen API绑定到具体DOM节点,当组件因状态变更重渲染时,若原来处于全屏的DOM元素被卸载或重新创建(比如组件重渲染生成新的DOM节点),浏览器会自动退出全屏状态。
具体解决方案
1. 固定全屏目标元素
用useRef锁定全屏容器的DOM节点,确保组件重渲染时该节点不会被销毁重建:
import { useRef } from 'react'; const Multipage = ({ activeSlide, slides }) => { const fullscreenContainerRef = useRef(null); const toggleFullscreen = () => { const container = fullscreenContainerRef.current; if (!container) return; if (!document.fullscreenElement) { container.requestFullscreen(); } else { document.exitFullscreen(); } }; return ( <div ref={fullscreenContainerRef} className="slides-container"> {slides[activeSlide]} <button onClick={toggleFullscreen}>全屏预览</button> </div> ); };
2. 减少不必要的重渲染
用React.memo包裹Multipage组件,自定义props比较逻辑,仅当幻灯片内容或激活页真的变化时才重渲染:
import { memo } from 'react'; const arePropsEqual = (prevProps, nextProps) => { return prevProps.activeSlide === nextProps.activeSlide && JSON.stringify(prevProps.slides) === JSON.stringify(nextProps.slides); }; const Multipage = memo(({ activeSlide, slides }) => { // 同上的全屏逻辑和渲染代码 }, arePropsEqual);
同时在父组件中用useMemo缓存slides数据,避免每次渲染生成新数组触发子组件重渲染:
import { useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import { slidesAtom } from './atoms'; function NewFormTemplate() { const [activeSlide, setActiveSlide] = useState(0); const rawSlides = useRecoilValue(slidesAtom); const memoizedSlides = useMemo(() => rawSlides, [rawSlides]); return ( <div> <Multipage activeSlide={activeSlide} slides={memoizedSlides} /> {/* 其他幻灯片控制组件 */} </div> ); }
3. 分离全屏控制逻辑
把全屏触发按钮放在独立组件中,避免按钮所在组件重渲染影响全屏状态:
const FullscreenToggle = () => { const toggleFullscreen = () => { const container = document.getElementById('slides-container'); if (!container) return; if (!document.fullscreenElement) { container.requestFullscreen(); } else { document.exitFullscreen(); } }; return <button onClick={toggleFullscreen}>全屏预览</button>; }; function NewFormTemplate() { return ( <div> <div id="slides-container"> <Multipage activeSlide={activeSlide} slides={memoizedSlides} /> </div> <FullscreenToggle /> </div> ); }
4. 备选:重渲染后恢复全屏状态
若无法完全避免重渲染,用useRef记录全屏状态,内容更新后自动恢复:
const Multipage = ({ activeSlide, slides }) => { const fullscreenRef = useRef(null); const wasFullscreen = useRef(false); useEffect(() => { const handleFullscreenChange = () => { wasFullscreen.current = !!document.fullscreenElement; }; document.addEventListener('fullscreenchange', handleFullscreenChange); return () => document.removeEventListener('fullscreenchange', handleFullscreenChange); }, []); useEffect(() => { if (wasFullscreen.current && !document.fullscreenElement) { fullscreenRef.current?.requestFullscreen(); } }, [activeSlide, slides]); // ... 全屏切换逻辑 };
内容的提问来源于stack exchange,提问作者Sreejith N
相关产品推荐
相关产品推荐

