前言
某个项目需要点击全屏按钮将页面中某个容器内的元素进行全屏显示便于用户操作,点击退出全屏时显示原来的页面内容
问题
1:指定元素全屏存在部分元素无法显示
记得之前看 FullScreen
相关API时有印象可以让某一元素直接全屏显示,随即变试了试,发现效果还不错,使用如下:
const targetEle = document.getElementById('fullscreenEle');
targetEle.requestFullscreen();
但是在实际的项目中使用变发现了问题,全屏貌似是将当前全屏的内容放入了一个虚拟的DOM视图中(貌似?没怎么研究原理),使用 F12 检索后发现如下:
全屏元素挂载在了 top-layer
DOM树下,这样会导致以下几个问题:
- 为该元素设置的背景样式会失效,显示为黑色(无法解决)
- 如果你在该页面中使用了类似于 ANT-Design-Vue 组件库中的
a-tooltip
/a-modal
等组件,这些组件默认是挂载在body
下的,无法显示在该全屏页面中
第二个问题的解决方案也很简单:
- 将整个document元素作为全屏的元素,然后通过JS去控制哪些元素不显示,哪些元素显示
- 将所有挂载在
body
元素上的悬浮提示、模态框等使用官方API挂载在需要全屏的元素之内即可
2.使用F11时关闭全屏无法监听按键事件
当用户使用F11的快捷键进入全屏后,再使用快捷键F11或者ESC退出全屏时,会发现并没有触发按键事件。这对于页面需要根据全屏状态显示不同内容的开发者来说是致命的。因为这将导致用户使用按钮进入全屏和使用快捷键进入全屏后页面某些元素的状态同步不正确从而导致一些Bug
查阅资料后发现,这应该是浏览器端做的限制,目的是“为了防止开发者使用JS强制用户不可退出全屏”,我认为这是合理的。
但我们如何达成自己想要的效果呢?很简单,重新实现以下按键F11的全屏功能即可
- 首先监听按键事件,当监听到用户点击
F11
时执行自定义的全屏逻辑 - 然后监听全屏事件,当用户使用
ESC
和F11
退出全屏时,可以通过该事件执行自己的逻辑,恢复某些按钮或元素的状态 - 组件卸载时取消监听按键事件,防止在其他页面仍然执行了该全屏逻辑
代码实现大致如下:
// 注:这里使用了 screenfull库,使用原生API也是一样的道理
// 页面渲染完成后监听按键事件执行自定义全屏逻辑
document.addEventListener('keydown', handleKeyDownEvent);
// 监听全屏改变事件,对应原生API中的 fullscreenchange 事件
screenfull.on('change', handleFullscreenEvent);
// 监听按键事件方法
function handleKeyDownEvent(event: KeyboardEvent): void {
if (event.key === 'F11') {
// 阻止默认行为并执行切换全屏逻辑
event.preventDefault();
toggleFullScreen();
}
}
// 切换全屏方法
function toggleFullScreen(): void {
if (screenfull.isFullscreen) {
isFullScreen.value = false;
screenfull.exit();
} else {
isFullScreen.value = true;
screenfull.request();
}
}
// 全屏切换事件
function handleFullscreenEvent(): void {
if (!screenfull.isFullscreen) {
isFullScreen.value = false;
}
}
// 组件卸载时移除监听事件
document.removeEventListener('keydown', handleKeyDownEvent);
screenfull.off('change', handleFullscreenEvent);
这样,不管用户使用快捷键进入全屏还是点击按钮全屏,所有元素的状态都可以保持一致
注意:
看到网上有人使用 resize
事件来监听退出全屏,虽然退出全屏时也会触发该事件,但是不应该使用该事件,因为该事件是文档窗口大小改变时才会触发,也就是说当你双击浏览器顶部放大缩小或者手动拖拽浏览器边角调整大小时都会触发该事件,此时就会误执行相关逻辑。
这里还是应该使用 fullscreenchange
事件去监听的,这是原生 FullScreen API中提供的,使用样例如下:
document.documentElement.addEventListener('fullscreenchange', () => {});
第三方库
虽然官方提供了 FullScreen API
,但是对于浏览器版本还是有限制的,且不同浏览器中的API也略有不同,如果自行实现的话需要对各个浏览器做适配,这里建议使用 screenfull 库
你可以通过它封装的API去简便的实现全屏逻辑,如下:
import screenfull from 'screenfull';
function toggleFullScreen(): void {
if (!screenfull.isEnabled) {
message.warn('当前浏览器版本不支持全屏');
return;
}
if (screenfull.isFullscreen) {
isFullScreen.value = false;
screenfull.exit();
} else {
isFullScreen.value = true;
screenfull.request();
}
}