FullScreen API与F11快捷键的相关问题排查与解决

前言

某个项目需要点击全屏按钮将页面中某个容器内的元素进行全屏显示便于用户操作,点击退出全屏时显示原来的页面内容

问题

1:指定元素全屏存在部分元素无法显示

记得之前看 FullScreen 相关API时有印象可以让某一元素直接全屏显示,随即变试了试,发现效果还不错,使用如下:

const targetEle = document.getElementById('fullscreenEle');
targetEle.requestFullscreen();

但是在实际的项目中使用变发现了问题,全屏貌似是将当前全屏的内容放入了一个虚拟的DOM视图中(貌似?没怎么研究原理),使用 F12 检索后发现如下:
在这里插入图片描述
全屏元素挂载在了 top-layer DOM树下,这样会导致以下几个问题:

  1. 为该元素设置的背景样式会失效,显示为黑色(无法解决)
  2. 如果你在该页面中使用了类似于 ANT-Design-Vue 组件库中的 a-tooltip / a-modal 等组件,这些组件默认是挂载在 body 下的,无法显示在该全屏页面中

第二个问题的解决方案也很简单:

  1. 将整个document元素作为全屏的元素,然后通过JS去控制哪些元素不显示,哪些元素显示
  2. 将所有挂载在 body 元素上的悬浮提示、模态框等使用官方API挂载在需要全屏的元素之内即可

2.使用F11时关闭全屏无法监听按键事件

当用户使用F11的快捷键进入全屏后,再使用快捷键F11或者ESC退出全屏时,会发现并没有触发按键事件。这对于页面需要根据全屏状态显示不同内容的开发者来说是致命的。因为这将导致用户使用按钮进入全屏和使用快捷键进入全屏后页面某些元素的状态同步不正确从而导致一些Bug

查阅资料后发现,这应该是浏览器端做的限制,目的是“为了防止开发者使用JS强制用户不可退出全屏”,我认为这是合理的。

但我们如何达成自己想要的效果呢?很简单,重新实现以下按键F11的全屏功能即可

  1. 首先监听按键事件,当监听到用户点击 F11 时执行自定义的全屏逻辑
  2. 然后监听全屏事件,当用户使用 ESCF11 退出全屏时,可以通过该事件执行自己的逻辑,恢复某些按钮或元素的状态
  3. 组件卸载时取消监听按键事件,防止在其他页面仍然执行了该全屏逻辑

代码实现大致如下:

// 注:这里使用了 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();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值