【xgplayer】xgplayer全屏模式优化实战 | 解决CSS全屏与播放器全屏切换冲突
1. 理解xgplayer全屏冲突的核心问题
第一次用xgplayer做移动端视频项目时,我就被这个全屏切换的坑折磨得不轻。明明在PC端测试好好的功能,到了手机上就出现视频"凭空消失"的灵异现象。后来发现这其实是CSS全屏和播放器原生全屏两种模式切换时的典型冲突。
具体表现是这样的:当你先用CSS全屏模式观看视频(这种模式特别适合9:16的竖屏视频),然后再切换到播放器自带的原生全屏模式时,缩小窗口后视频容器会神秘失踪,只留下孤零零的控制按钮。这是因为两种全屏模式对DOM元素的处理方式不同:
- CSS全屏:通过修改元素的class实现视觉填充,不改变DOM结构
- 原生全屏:浏览器API会将元素移出当前文档流,放入全屏专用层
// 问题重现代码示例 player.on('exitFullscreen', () => { // 退出原生全屏时,CSS全屏元素可能已经不在预期位置 videoContainer.style.display = 'none'; // 这就是视频消失的原因 });2. 两种全屏模式的本质区别
要彻底解决这个问题,得先明白两种全屏的技术原理。去年我做短视频项目时,就因为这个知识点没吃透,导致上线后出现大量用户投诉。
CSS全屏模式:
- 通过绝对定位+固定宽高模拟全屏效果
- 优点:保持DOM结构不变,适合特殊比例视频
- 缺点:地址栏等浏览器UI仍然可见
原生全屏模式:
- 调用
element.requestFullscreen()API - 优点:真正的全屏体验,隐藏所有浏览器UI
- 缺点:会改变元素层级关系,导致CSS定位失效
/* CSS全屏的典型实现 */ .css-fullscreen { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 9999; }3. 完整解决方案实现步骤
经过三个项目的实战验证,我总结出这个稳定可用的解决方案。关键是要在两种全屏模式切换时,正确处理按钮的显隐状态和元素层级关系。
3.1 基础配置准备
首先确保正确导入xgplayer的必要模块。这里有个坑要注意:不同版本的导入路径可能不同,建议直接指定完整路径。
import Player from 'xgplayer/dist/simple_player'; import cssFullscreen from 'xgplayer/dist/controls/cssFullscreen'; import { toggleClass } from 'xgplayer/src/utils/util'; const playerOpts = { id: 'player', url: 'video.mp4', cssFullscreen: true, // 必须开启此选项 controlPlugins: [ cssFullscreen // 添加CSS全屏按钮 ] };3.2 事件监听与状态同步
核心逻辑在于这两个事件监听器。我在实际项目中发现,必须在ready事件之后才能安全操作DOM元素,否则可能找不到按钮节点。
player.once('ready', () => { const fullScrBtn = document.querySelector('#player .xgplayer-fullscreen'); // 进入CSS全屏时隐藏原生全屏按钮 player.on('requestCssFullscreen', () => { toggleClass(fullScrBtn, 'hide'); // 额外保险:强制设置display属性 fullScrBtn.style.display = 'none'; }); // 退出CSS全屏时恢复按钮 player.on('exitCssFullscreen', () => { toggleClass(fullScrBtn, 'hide'); fullScrBtn.style.display = ''; }); });3.3 CSS样式加固
光靠JS控制还不够稳定,我建议加上这些CSS规则作为双重保障。特别注意scoped样式的问题,这在Vue项目中很常见。
#player >>> .xgplayer-fullscreen.hide { display: none !important; visibility: hidden !important; } /* 处理移动端特殊场景 */ @media (orientation: portrait) { #player >>> .xgplayer-css-fullscreen { z-index: 10000; } }4. 移动端特殊场景处理
在最近的一个跨平台项目中,我发现iOS设备上还有额外的问题需要处理。特别是当设备旋转时,全屏状态可能会异常退出。
4.1 横竖屏适配方案
针对不同比例的视频,需要动态调整全屏策略。这是我的经验方案:
- 16:9视频:优先使用原生全屏
- 9:16视频:强制使用CSS全屏
- 其他比例:根据设备方向自动选择
// 检测视频比例决定全屏模式 function checkVideoRatio(url) { return new Promise((resolve) => { const video = document.createElement('video'); video.src = url; video.onloadedmetadata = () => { const ratio = video.videoWidth / video.videoHeight; resolve(ratio > 1 ? 'native' : 'css'); }; }); }4.2 防止意外退出的技巧
在orientationchange事件中添加这些处理逻辑,可以避免很多奇怪的bug:
window.addEventListener('orientationchange', () => { if(player.isFullscreen) { // 保持全屏状态 player.exitFullscreen(); setTimeout(() => player.requestFullscreen(), 100); } });5. 进阶优化建议
经过多个项目迭代,我总结出这些提升用户体验的技巧:
5.1 平滑过渡动画
突然消失的按钮会让用户困惑,添加过渡效果会更自然:
#player >>> .xgplayer-fullscreen { transition: opacity 0.3s ease; } #player >>> .xgplayer-fullscreen.hide { opacity: 0; }5.2 状态持久化方案
使用localStorage记住用户最后一次使用的全屏模式:
player.on('requestFullscreen', () => { localStorage.setItem('preferredFullscreen', 'native'); }); player.on('requestCssFullscreen', () => { localStorage.setItem('preferredFullscreen', 'css'); });5.3 性能优化技巧
全屏切换时注意这些性能陷阱:
- 避免频繁重排重绘
- 使用will-change提前告知浏览器
- 对视频解码器做预热处理
// 预加载解码器 player.video.addEventListener('loadeddata', () => { player.video.pause(); player.video.currentTime = 0.1; });6. 常见问题排查指南
遇到问题时,可以按照这个检查清单逐步排查:
元素选择器是否正确
使用Chrome开发者工具检查按钮的实际class名事件触发顺序问题
在控制台输出各事件的触发时间戳z-index层级冲突
使用3D视图检查元素堆叠关系移动端浏览器兼容性
特别注意iOS的PWA模式下全屏API的限制
// 调试事件监听 player.on('requestCssFullscreen', () => { console.time('cssFullscreen'); }); player.on('exitCssFullscreen', () => { console.timeEnd('cssFullscreen'); });7. 实际项目中的经验分享
去年开发教育类APP时,我们遇到了一个棘手情况:当老师在PPT全屏模式下点击视频全屏时,会导致PPT布局错乱。最终解决方案是:
- 检测到PPT处于全屏状态时,禁用视频原生全屏
- 使用CSS全屏时,动态调整视频层级
- 添加中间过渡层防止z-index穿透
// PPT全屏时的特殊处理 document.addEventListener('pptFullscreenChange', (e) => { if(e.detail.isFullscreen) { playerConfig.cssFullscreen = true; player.updateConfig(playerConfig); } });这个案例告诉我,全屏交互不能孤立考虑,必须放在具体业务场景中验证。现在我的团队都会在需求阶段就明确全屏策略,避免后期返工。
