9.3 全屏API
9.3 全屏API
全屏API允许Web开发者以编程方式控制元素的全屏显示,为视频播放、游戏、演示等场景提供沉浸式体验。本节将详细介绍全屏API的使用方法、兼容性处理和最佳实践。
基础API使用
1. 全屏模式切换
// 进入全屏模式
function enterFullscreen(element) {
if (element.requestFullscreen) {
return element.requestFullscreen();
} else if (element.webkitRequestFullscreen) { /* Safari */
return element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) { /* IE11 */
return element.msRequestFullscreen();
}
return Promise.reject('Fullscreen API is not supported');
}
// 退出全屏模式
function exitFullscreen() {
if (document.exitFullscreen) {
return document.exitFullscreen();
} else if (document.webkitExitFullscreen) { /* Safari */
return document.webkitExitFullscreen();
} else if (document.msExitFullscreen) { /* IE11 */
return document.msExitFullscreen();
}
return Promise.reject('Fullscreen API is not supported');
}
// 切换全屏状态
function toggleFullscreen(element) {
if (!document.fullscreenElement) {
return enterFullscreen(element);
} else {
return exitFullscreen();
}
}
// 使用示例
document.getElementById('fullscreen-btn').addEventListener('click', () => {
toggleFullscreen(document.documentElement).catch(err => {
console.error('全屏操作失败:', err);
});
});
2. 全屏状态检测
// 获取当前全屏状态
function getFullscreenState() {
return {
isFullscreen: !!(
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement
),
element: (
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement
)
};
}
// 监听全屏变化事件
function setupFullscreenListeners() {
const events = [
'fullscreenchange',
'webkitfullscreenchange',
'MSFullscreenChange'
];
events.forEach(event => {
document.addEventListener(event, () => {
const state = getFullscreenState();
console.log('全屏状态变化:', state.isFullscreen);
updateUIForFullscreen(state.isFullscreen);
});
});
}
// 初始化
setupFullscreenListeners();
高级功能实现
1. 全屏样式定制
/* 全屏模式专用样式 */
:fullscreen, ::backdrop {
background-color: #000;
}
/* 浏览器前缀兼容 */
:-webkit-full-screen, :-webkit-full-screen-ancestor {
background-color: #000;
}
:-moz-full-screen, :-moz-full-screen-ancestor {
background-color: #000;
}
:-ms-fullscreen, :-ms-fullscreen-ancestor {
background-color: #000;
}
/* 全屏时的自定义样式 */
#content:fullscreen {
display: flex;
flex-direction: column;
justify-content: center;
}
/* 背景幕布样式 */
::backdrop {
background: linear-gradient(135deg, #1e3c72, #2a5298);
}
2. 全屏提示与限制处理
class FullscreenManager {
constructor() {
this.supported = this.checkSupport();
this.setupEventListeners();
}
checkSupport() {
return !!(
document.fullscreenEnabled ||
document.webkitFullscreenEnabled ||
document.msFullscreenEnabled
);
}
setupEventListeners() {
document.addEventListener('fullscreenerror', (e) => {
console.error('全屏错误:', e);
this.showErrorMessage('无法进入全屏模式,请检查浏览器设置');
});
document.addEventListener('click', (e) => {
if (e.target.classList.contains('fullscreen-toggle')) {
this.handleFullscreenRequest(e.target);
}
}, true);
}
async handleFullscreenRequest(button) {
if (!this.supported) {
this.showErrorMessage('您的浏览器不支持全屏功能');
return;
}
try {
const targetElement = button.dataset.target
? document.querySelector(button.dataset.target)
: document.documentElement;
if (!targetElement) throw new Error('目标元素不存在');
const state = this.getState();
if (state.isFullscreen) {
await this.exit();
button.textContent = '进入全屏';
} else {
await this.enter(targetElement);
button.textContent = '退出全屏';
}
} catch (error) {
console.error('全屏操作失败:', error);
this.showErrorMessage(error.message);
}
}
getState() {
return {
isFullscreen: !!(
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement
),
element: (
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement
)
};
}
enter(element) {
if (element.requestFullscreen) {
return element.requestFullscreen();
} else if (element.webkitRequestFullscreen) {
return element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) {
return element.msRequestFullscreen();
}
throw new Error('全屏API不可用');
}
exit() {
if (document.exitFullscreen) {
return document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
return document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
return document.msExitFullscreen();
}
throw new Error('退出全屏API不可用');
}
showErrorMessage(msg) {
const alert = document.createElement('div');
alert.className = 'fullscreen-alert';
alert.textContent = msg;
document.body.appendChild(alert);
setTimeout(() => alert.remove(), 3000);
}
}
// 初始化
const fullscreenManager = new FullscreenManager();
兼容性处理方案
1. 前缀统一封装
// 统一前缀的API访问
const fullscreen = {
request: function(element) {
const methods = [
'requestFullscreen',
'webkitRequestFullscreen',
'webkitRequestFullScreen', // 旧版Safari
'msRequestFullscreen'
];
for (let method of methods) {
if (element[method]) {
return element[method]();
}
}
return Promise.reject('不支持全屏API');
},
exit: function() {
const methods = [
'exitFullscreen',
'webkitExitFullscreen',
'webkitCancelFullScreen', // 旧版Safari
'msExitFullscreen'
];
for (let method of methods) {
if (document[method]) {
return document[method]();
}
}
return Promise.reject('不支持退出全屏API');
},
get enabled() {
return !!(
document.fullscreenEnabled ||
document.webkitFullscreenEnabled ||
document.msFullscreenEnabled
);
},
get element() {
return (
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement
);
},
get isActive() {
return !!this.element;
},
onChange: function(callback) {
const events = [
'fullscreenchange',
'webkitfullscreenchange',
'MSFullscreenChange'
];
const handler = () => callback(this.isActive);
events.forEach(event => {
document.addEventListener(event, handler);
});
// 返回取消监听函数
return () => {
events.forEach(event => {
document.removeEventListener(event, handler);
});
};
}
};
// 使用示例
fullscreen.onChange(isFullscreen => {
console.log('全屏状态变化:', isFullscreen);
});
document.getElementById('toggle-fs').addEventListener('click', () => {
if (fullscreen.isActive) {
fullscreen.exit();
} else {
fullscreen.request(document.getElementById('video'));
}
});
2. 移动端特殊处理
// 检测移动设备
function isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
// 移动端全屏处理
function setupMobileFullscreen() {
if (!isMobileDevice()) return;
// 禁用iOS默认全屏行为(视频元素)
const videos = document.querySelectorAll('video');
videos.forEach(video => {
video.setAttribute('playsinline', '');
video.setAttribute('webkit-playsinline', '');
});
// 添加手势控制
let fsTimeout;
document.addEventListener('dblclick', () => {
clearTimeout(fsTimeout);
fsTimeout = setTimeout(() => {
toggleFullscreen(document.documentElement);
}, 300);
});
// 处理键盘弹出
window.addEventListener('resize', () => {
if (window.innerHeight < document.documentElement.clientHeight * 0.8) {
fullscreen.exit();
}
});
}
实际应用案例
1. 视频播放器全屏控制
class VideoPlayer {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.video = this.container.querySelector('video');
this.controls = this.container.querySelector('.controls');
this.setupEvents();
}
setupEvents() {
// 全屏按钮
const fsBtn = this.controls.querySelector('.fullscreen-btn');
fsBtn.addEventListener('click', () => this.toggleFullscreen());
// 全屏状态变化
document.addEventListener('fullscreenchange', () => {
this.updateControls();
});
// 键盘控制
document.addEventListener('keydown', (e) => {
if (!fullscreen.isActive) return;
switch(e.key) {
case 'Escape':
this.exitFullscreen();
break;
case 'f':
this.toggleFullscreen();
break;
}
});
}
async toggleFullscreen() {
try {
if (fullscreen.isActive) {
await fullscreen.exit();
} else {
await fullscreen.request(this.container);
this.video.focus();
}
} catch (error) {
console.error('全屏切换失败:', error);
}
}
updateControls() {
const fsBtn = this.controls.querySelector('.fullscreen-btn');
if (fullscreen.isActive) {
fsBtn.innerHTML = '<svg>...</svg> 退出全屏';
this.container.classList.add('fullscreen-active');
} else {
fsBtn.innerHTML = '<svg>...</svg> 全屏';
this.container.classList.remove('fullscreen-active');
}
}
async exitFullscreen() {
if (fullscreen.isActive) {
await fullscreen.exit();
}
}
}
// 初始化播放器
const player = new VideoPlayer('video-player');
2. 游戏全屏优化
class GameEngine {
constructor() {
this.canvas = document.getElementById('game-canvas');
this.ctx = this.canvas.getContext('2d');
this.isFullscreen = false;
this.setupFullscreen();
}
setupFullscreen() {
// 自动调整画布尺寸
const resizeCanvas = () => {
if (this.isFullscreen) {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
} else {
this.canvas.width = 800;
this.canvas.height = 600;
}
this.render();
};
// 监听全屏变化
fullscreen.onChange(isFullscreen => {
this.isFullscreen = isFullscreen;
resizeCanvas();
});
// 初始调整
resizeCanvas();
// 双击切换全屏
this.canvas.addEventListener('dblclick', () => {
if (this.isFullscreen) {
fullscreen.exit();
} else {
fullscreen.request(this.canvas);
}
});
}
render() {
// 渲染逻辑...
this.ctx.fillStyle = '#333';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
// 显示当前模式
this.ctx.fillStyle = '#fff';
this.ctx.font = '24px Arial';
this.ctx.fillText(
this.isFullscreen ? '全屏模式(双击退出)' : '窗口模式(双击全屏)',
20, 40
);
}
}
// 启动游戏
const game = new GameEngine();
安全与最佳实践
-
用户触发原则:
- 全屏请求必须由用户手势(点击、按键等)直接触发
- 不能通过setTimeout或异步回调自动触发
-
视觉反馈:
- 全屏状态变化时提供清晰的UI反馈
- 在全屏模式下提供明显的退出选项
-
键盘导航:
// 确保ESC可以退出全屏 document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && fullscreen.isActive) { fullscreen.exit(); } }); -
性能优化:
// 全屏时启动高性能渲染 fullscreen.onChange(isFullscreen => { if (isFullscreen) { startHighPerformanceMode(); } else { stopHighPerformanceMode(); } });
全屏API为Web应用提供了强大的展示能力,开发时应注意:
- 始终尊重用户控制权,避免强制全屏
- 处理不同浏览器的前缀差异
- 为移动设备提供特殊优化
- 在全屏模式下保持必要的UI控制元素
- 考虑无障碍访问需求
通过合理使用全屏API,可以显著提升媒体展示、游戏和交互应用的沉浸感和用户体验。
#前端开发
分享于 2025-05-20
上一篇:9.2 设备方向与运动检测
下一篇:9.4 通知 API