最近的开发工作中遇到了一个需求是在pc或者pad上可以像ppt一样全屏显示当前页面的内容。在这里记录一下开发过程中遇到的问题。
web 提供的全屏API
Document.fullscreenEnabled // 是否支持全屏模式
Element.requestFullscreen() // 发出异步请求进入全屏模式
Document.exitFullscreen() // 退出全屏
Document.onfullscreenchange() // 进入或退出全屏时触发的事件
Document.onfullscreenerror() // 当浏览器无法进入全屏模式时会触发该事件
Document.fullscreenElement() // 返回当前的全屏元素或者当前没有全屏元素返回null
- 全屏模式,只能由用户行为触发。比如无法一进入页面就由JS直接调起全屏,此时会有错误提示。
- 用户可以选择按ESC(或F11) 键退出全屏模式。此行为为系统级别的事件,无法在浏览器中捕捉或监听该操作。
class 封装全屏API
interface htmlElement extends Document {
// 是否支持全屏
webkitFullscreenEnabled: boolean;
mozFullScreenEnabled: boolean;
msFullscreenEnabled: boolean;
// 是否具有全屏元素
msFullscreenElement: Element;
mozFullScreenElement: Element;
webkitFullscreenElement: Element;
}
class FullScreen {
private _prefixName = ''; // 各浏览器前缀
private _isSupportFullscreen = true; // 浏览器是否支持
private _dom: HTMLDivElement | null = null;
constructor() {
this._getPrefix();
}
get isSupportFullscreen(): boolean {
return this._isSupportFullscreen;
}
private _getPrefix(): void {
let fullscreenEnabled;
const doc = document as htmlElement;
// 判断浏览器前缀
if (doc.fullscreenEnabled) {
fullscreenEnabled = doc.fullscreenEnabled;
} else if (doc.webkitFullscreenEnabled) {
fullscreenEnabled = doc.webkitFullscreenEnabled;
this._prefixName = 'webkit';
} else if (doc.mozFullScreenEnabled) {
fullscreenEnabled = doc.mozFullScreenEnabled;
this._prefixName = 'moz';
} else if (doc.msFullscreenEnabled) {
fullscreenEnabled = doc.msFullscreenEnabled;
this._prefixName = 'ms';
}
if (!fullscreenEnabled) {
this._isSupportFullscreen = false;
console.log('This browser does not support full screen!');
}
}
/**
* @description: 将传进来的元素全屏
* @param {String} domName 要全屏的dom名称
*/
public requestFullscreen(dom: string): void {
if (!this._isSupportFullscreen || !this._dom) {
return;
}
const methodName = (
this._prefixName === '' ? 'requestFullscreen' : `${this._prefixName}RequestFullScreen`
) as 'requestFullscreen';
this._dom?.[methodName]().catch((err) => {
alert(`An error occurred while trying to switch into fullscreen mode: ${err.message} (${err.name})`);
});
}
/**
* @description: 退出全屏
*/
public exitFullscreen(): void {
if (!this._isSupportFullscreen || !this.isElementFullScreen()) {
return;
}
const methodName = (
this._prefixName === '' ? 'exitFullscreen' : `${this._prefixName}ExitFullscreen`
) as 'exitFullscreen';
document[methodName]();
}
/**
* @description: 监听进入/离开全屏
* @param {Function} enter 进入全屏的回调
* @param {Function} quit 离开全屏的回调
*/
public screenChange(enter: (e: Event) => void, quit: (e: Event) => void): void {
if (!this._isSupportFullscreen) return;
const methodName = `on${this._prefixName}fullscreenchange` as 'onfullscreenerror';
document[methodName] = (e: Event): void => {
if (this.isElementFullScreen()) {
this._dom?.classList.add('fullscreen');
enter && enter(e); // 进入全屏回调
} else {
quit && quit(e); // 离开全屏的回调
this._dom?.classList.remove('fullscreen');
}
};
}
/**
* @description: 浏览器无法进入全屏时触发,可能是技术原因,也可能是用户拒绝:比如全屏请求不是在事件处理函数中调用,会在这里拦截到错误
* @param {Function} enterErrorFn 回调
*/
public screenError(enterErrorFn: (e: Event) => void): void {
if (!this._isSupportFullscreen) return;
const methodName = `on${this._prefixName}fullscreenerror` as 'onfullscreenerror';
document[methodName] = (e: Event): void => {
enterErrorFn && enterErrorFn(e);
};
}
/**
* @description: 检测有没有元素处于全屏状态
* @return 布尔值
*/
public isElementFullScreen(): boolean {
const doc = document as htmlElement;
const fullscreenElement =
doc.fullscreenElement || doc.msFullscreenElement || doc.mozFullScreenElement || doc.webkitFullscreenElement;
return !!fullscreenElement;
}
/**
* @description: 打开全屏
* @param {string} 全屏元素
*/
public open(dom: string, enter?: (e: Event) => void, quit?: (e: Event) => void): void {
if (!dom || !document.querySelector(dom)) {
return;
}
this._dom = document.querySelector(dom);
this.requestFullscreen(dom);
this.screenChange(enter as (e: Event) => void, quit as (e: Event) => void);
this.screenError(() => {
console.log('Failed to enter full screen!');
});
}
}
export default new FullScreen();
全屏兼容问题
在这次的开发中主要是在PC或pad上全屏,所以兼容性也只是针对这两种设备。
1. 部分ipad在 chrome 浏览器下不支持全屏
developer.mozilla.org/en-US/docs/…
2. :fullscreen 兼容性不好,不建议使用
developer.mozilla.org/en-US/docs/…
有另外的解决方案:在进入或退出全屏时添加class进行全屏样式的设置
// Fullscreen.screenChange
document[methodName] = (e: Event): void => {
if (this.isElementFullScreen()) {
this._dom?.classList.add('fullscreen');
enter && enter(e); // 进入全屏回调
} else {
quit && quit(e); // 离开全屏的回调
this._dom?.classList.remove('fullscreen');
}
};
3. esc退出全屏
当设备为pad时,没有esc按键,无法按esc键退出全屏,但是部分设备可以使用向下滑动退出全屏。
有些设备不支持向下滑动退出全屏,比如三星pad在三星浏览器。
所以建议在pad平台上添加显式按钮退出全屏。
private _renderCloseBtn = (): void => {
// 是否是pad
if (isPad()) {
const btn = document.createElement('button');
btn.textContent = 'Exit';
this._closeBtn = document.createElement('div');
this._closeBtn.appendChild(btn);
this._closeBtn.classList.add('fullscreen-close');
this._dom?.appendChild(this._closeBtn);
}
};