React+TypeScript视频网站问题求助:页面刷新与iOS兼容性
问题1:刷新模板页时state丢失导致异常的解决方案
核心原因
useLocation().state仅存在于内存路由导航过程中,页面刷新后浏览器会重新加载页面,state数据会被清空,直接解构location.state会抛出类型错误,进而引发页面异常。
修复步骤
- 添加状态检查与重定向:在组件中先判断state是否存在,不存在则立即重定向到首页,并用
replace: true避免错误页面留在历史栈。 - 安全解构state数据:使用可选链操作符避免空值解构报错,同时设置默认值保证组件正常渲染。
- 修正DOM副作用位置:将操作
document.body.style.overflow的代码移至useEffect,避免组件重复渲染时多次执行。 - 修复未定义变量:补充代码中缺失的
selectedVideoIndex状态定义。
修改后的代码片段
import React, { useState, useEffect } from 'react'; import './Grille_video_style.css'; import { useLocation, useNavigate } from 'react-router-dom'; import styled from '@emotion/styled'; //Adaptable web/phone style const ContainerStyle = styled.div` top: 0; left: 0; position: fixed; width: 100%; height: 100vh; justify-content: center; background-color: black; //Adaptation for phone @media (max-width: 85em) { width: 70%; } `; const Grille_video: React.FC = () => { const location = useLocation(); const navigate = useNavigate(); // 补充未定义的选中视频索引状态 const [selectedVideoIndex, setSelectedVideoIndex] = useState(0); const [isMobile, setIsMobile] = useState<boolean>(window.matchMedia('(max-width: 85em)').matches); // 检查state是否存在,不存在则重定向到首页 useEffect(() => { if (!location.state?.paths) { navigate('/Grille', { replace: true }); } }, [location.state, navigate]); // 安全获取视频路径数据,避免空值报错 const paths = location.state?.paths || []; const [videos, setVideos] = useState(paths); // 处理页面滚动禁用与组件卸载时的恢复 useEffect(() => { document.body.style.overflow = 'hidden'; return () => { document.body.style.overflow = 'auto'; }; }, []); // 返回按钮点击事件 const handleBackClick = () => { document.exitFullscreen().catch(err => console.log(err)); navigate('/Grille'); }; // 监听窗口大小变化,判断是否为移动端 useEffect(() => { const handleResize = () => { setIsMobile(window.matchMedia('(max-width: 85em)').matches); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return ( <ContainerStyle> <button onClick={handleBackClick} style={styles.backButton}> Retour </button> {videos.map((src, index) => ( <video key={index} style={styles.videoMain} controls={isMobile ? selectedVideoIndex === index : true} autoPlay loop muted className="custom-video" preload="auto" > <source src={src} type="video/mp4" /> Your browser does not support the video tag. </video> ))} </ContainerStyle> ); }; const styles: { [key: string]: React.CSSProperties | any } = { backButton: { position: 'absolute', top: '10px', left: '10px', padding: '10px 20px', backgroundColor: '#EA6666', color: 'white', border: 'none', borderRadius: '8px', cursor: 'pointer', zIndex: 1100, }, videoMain: { position: 'absolute', width: '100vw', height: 'calc(100vh - 50px)', objectFit: 'cover', opacity: 1, zIndex: 1000, }, }; export default Grille_video;
问题2:iPhone设备兼容解决方案
核心思路
iOS Safari存在大量与安卓浏览器的特性差异,需从CSS前缀、视频行为、触摸事件、viewport配置等维度针对性适配,优先使用特性检测而非设备型号检测。
具体适配方案
基础viewport配置
确保HTML头部的viewport标签包含viewport-fit=cover,解决刘海屏、灵动岛的布局适配问题:<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">CSS属性兼容
- 对
object-fit等属性添加-webkit前缀,兼容旧版iOS Safari:.custom-video { object-fit: cover; -webkit-object-fit: cover; } - 解决iOS滚动时fixed定位元素抖动问题:
body { -webkit-overflow-scrolling: touch; } - 优化字体渲染效果:
* { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
- 对
视频播放行为适配
- iOS Safari对
autoPlay有严格限制,需同时设置muted和playsinline(避免自动全屏):<video ... playsinline muted autoPlay > - 若需统一跨设备控制栏样式,建议实现自定义视频控制组件,避免依赖原生控件差异。
- iOS Safari对
触摸与交互适配
- 解决iOS点击300ms延迟问题:
button, .custom-video { touch-action: manipulation; } - 优先使用
pointerdown/pointerup事件替代touch/click,实现跨设备交互统一。
- 解决iOS点击300ms延迟问题:
调试与问题定位
- 使用Safari开发者工具连接iPhone设备,实时查看控制台错误、DOM结构与样式计算结果。
- 针对特定场景,可临时通过
navigator.userAgent检测iOS环境做兼容(仅作为最后手段):const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
参考资源
- Safari官方WebKit兼容性文档,查询iOS Safari支持的Web特性
- MDN浏览器兼容性表格,检索CSS/JS API的设备支持情况
- caniuse,查询前端特性的跨设备支持数据
- 苹果开发者网站的Web开发指南,获取iOS适配最佳实践
内容的提问来源于stack exchange,提问作者PierreCode
相关产品推荐
相关产品推荐

