小知识,大挑战!本文正在参与「程序员必备小知识」创作活动。
本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
首先别骂标题党!这篇文章会从原生 dom api 开始,一路聊到 react 及相关组件库在全屏下的行为和应对措施,力求让你真正懂得如何和浏览器全屏打交道。如果你正打算实现一个全屏需求,那么本文绝对可以帮助你少往坑里踩。
废话少说,直接开始。
如何进入和退出全屏
如果现在项目经理跑过来告诉你,要加一个按钮,点一下就会把页面里某个表格全屏了,能做到吧。
简单!你想也没想就回答了。我直接 打开百度 大笔一挥,下面的实现就写好了,还附赠良好的兼容性:
很好,没什么问题,写个小 demo 测试一下:
nice!按钮的提示也正常变更,div 也正确的被全屏,堪称完美。对于大多数人来说,对于浏览器全屏的了解就到此为止了(我也一样),但是本文不会到此结束,不知道你有没有发现,这个 demo 里还是有问题存在的:
按 Esc 的时候也会退出全屏,但是此时按钮没有被正确修改(依旧显示“退出全屏”)。
看来这个办法不行,应该通过其他更可靠的方法来修改按钮状态,比如监听对应的事件?
如何监听全屏事件
然后你又打开了搜索引擎,这时候查到的内容明显嘈杂了起来,有人说可以监听 esc
的 keydown
事件,有人说不好,应该监听 onresize
事件,然后通过 document.fullscreen
判断是否全屏了:
你想了想,感觉都不怎么靠谱。确实,你想的没错,这些网上抄来抄去的文章大都已经过时了,监听 keydown 可以,但是我们同时还要监听 F11 的 keydown(按 F11 也可以退出全屏),这样的解决办法会显得比较复杂且不可靠。
而 onresize 更是调整尺寸的时候也会触发,不加防抖的监听会带来无用的性能消耗。并且 document.fullscreen
属性更是已经被弃用了:
那么当下(2021/10/21)最好的写法是什么样的呢?答案是使用 fullscreenchange
事件和 document.fullscreenElement
,如下:
fullscreenchange 可以挂在任何 dom 元素上,而 document.fullscreenElement 则可以获取到当前正在全屏的元素(为 null
时说明没有全屏)。
到这里,我们已经了解了浏览器全屏的主要 api,那么我们干脆一鼓作气,看一下全部的全屏相关 api 都有那些吧(别紧张,并不多)。
浏览器全屏相关 API
我们可以在 这里 找到全屏相关的所有 api。首先就是两个主要 API,进入全屏和退出全屏:
这里需要提一嘴,很多人在不太了解的时候都会以为一共有四个 api(element 上的进入、退出全屏,document 上的进入、退出全屏 ),但是实际上它只有两个:调用指定 element 上的 requestFullscreen
让这个元素进入全屏 以及 调用全局的 document.exitFullscreen 来退出全屏。
然后是属性,只有两个 Document.fullscreenElement 和 document.fullscreenEnabled,第一个咱们刚才已经用过了,全局只会有一个被全屏的 dom 元素,可以通过 fullscreenElement 拿到它。而 fullscreenEnabled
则可以用来判断当前是否支持全屏,它还有一个如下的兼容写法:
注意这两者的区别,fullscreenElement
全屏时有值,不全屏时没值,而 fullscreenEnabled
则只要当前支持全屏就会一直为 true
。
最后就是事件啦,也是只有两个 fullscreenchange 和 fullscreenerror。顾名思义,全屏状态切换时触发,全屏失败时触发,我们刚才也用到了,没什么好说的。
在 react 中使用全屏
这里顺便贴一下上面的使用方法在 react hook 里的实现,使用了 antd 作为组件库,直接复制就能用:
用法也很简单,这个文件导出了一个 FullScreenBtn
组件,把要全屏的元素 ref 传递给 targetRef
属性即可。也可以使用 onChange 来监听全屏状态变更事件。
OK,聊完了用法,现在我们来看一下全屏时会遇到的一些问题:
TypeError: fullscreen error
在有些时候调用 element.requestFullscreen()
会出现这个错误:
其实我们可以提前使用刚才提到的 fullscreenEnabled
来进行预判:
导致这个问题的原因时什么呢?很简单,这个元素处在一个 iframe 里,而这个 iframe 不允许全屏。其实也有 其他原因 可能会导致这个报错,但是我们基本遇不到。
解决办法也很简单,找到对应的 iframe,在其 sandbox
属性里添加 allow-fullscreen
即可:
关于 iframe 的 sandbox 属性可以看 iframe: The Inline Frame element - HTML: HyperText Markup Language | MDN (mozilla.org)。
为什么有时候进入全屏了按 Ecs 会没用?
相信很多人都遇到过这个问题,全屏之后按 Ecs 发现怎么都退不出来,只能按 F11 或者鼠标挪到最上面点 ×。而导致这个问题的原因说起来也挺悲哀:浏览器中存在两套全屏规则!
- 第一套就是我们刚才讲的,通过 web API 进入的全屏。此时 可以通过 Esc 和 F11 退出全屏,也可以通过 api 正常监听和退出全屏。
- 第二套则是浏览器级别的全屏,通过 F11(或右上角设置里的全屏按钮)进入的全屏。此时 只能通过 F11 退出全屏。
这两者在进入全屏时给出的浏览器提示也是不一样的:
那么悲哀在那里呢?悲哀在 第二种方式进入的全屏是无法通过 api 访问到的!
如果你不信的话,可以尝试下,现在按 F11 打开全屏后在控制台输入以下代码,你会发现即使是浏览器已经全屏了,api 也完全不知道:
针对第二种全屏方式的监听一直是很多人讨论的问题,例如老办法,监听 F11
的 keydown 事件(但是无法处理点击浏览器右上角全屏按钮 ),或者在 onresize
里监听 window.outterHeight
和 window.innerHeight
的差异(某些浏览器里全屏后者两者并不是完全相同,存在兼容性问题 )。
这个问题目前我没找到合适的解决办法,如果有人有好点子的话欢迎评论分享。
全屏后都黑了?聊聊与全屏相关的 CSS
在实际开发的时候,有时候我们会遇到一些比较让人崩溃的样式问题,例如 element 官网上一个很正常的表单:
使用 requestFullscreen
将其全屏之后:
nooooooooooooooo!表单你怎么了!看到这一幕相信很多人心嘎吱一下就凉了半截,完了这么大的样式问题,不好处理。其实不用担心,这只是默认的用户代理样式表在作怪,我们打开控制台选中一下被全屏的 dom,在样式最下面就能看到罪魁祸首:
这里简单介绍一下::fullscreen
伪类代表了被全屏后的元素本身,而 ::backdrop
伪元素代表了全屏之后的背景画面(比如一个元素全屏之后没办法铺满整个窗口 )。了解了原因之后就很好解决了,毕竟用户代理样式表的优先级是相当低的,我们稍微写一下就能覆盖它们:
而 :fullscreen
则可以用来解决一些更实际的问题,例如:
- 被全屏元素没有指定内边框导致直接贴住了窗口边缘。
- 被全屏元素内容超出屏幕但是却滚动不了。
都可以用下面的样式来解决:
关于这两者的详细介绍见:::backdrop - CSS(层叠样式表) | MDN (mozilla.org) 和 :fullscreen - CSS(层叠样式表) | MDN (mozilla.org)。
弹出表单项被遮挡问题
这次我们换 antd 官网来霍霍,打开 表单 Form - Ant Design,然后 F12 把这个元素全屏,然后就会发现,嗯弹出表单怎么点不动了?
造成这个问题的原因是这些组件库实现弹出框的做法一般都是在 body 下创建对应的 dom 节点,而我们全屏了某个 body 下的 dom 元素后,这些弹出框的 dom 节点就被我们的全屏元素盖住了,自然就看不到了,那么怎么解决呢?
首先是比较优雅的方案,绝大多数主流组件库的弹出式组件都会给你提供这么一个方法。element 里则是 popper-append-to-body
属性:
我们就可以用它来解决这个问题,例如我们使用了上文里给的全屏按钮,只需要把要全屏的 dom ref 扔进去就好了:
但是如果我们用不了这个办法,比如组件库没有提供这个属性,又或者要全屏的 dom 元素里有好多要弹出的组件。那么该怎么办呢?没有问题,这里再给一个不太优雅但是同样有效的方案,全屏整个 Document,然后修改要展示的节点样式,让其覆盖住整个窗口:
注意这种方法一定要检查会不会引发一些样式问题。
写在最后
本文介绍了如何优雅的使用现代全屏 API。以及对在开发全屏需求时可能会遇到的一些问题和坑,希望对大家有所帮助,觉得可以的话不要吝啬点赞哦。
如果看完之后你觉得不够尽兴的话,那么推荐读一下 Guide to the Fullscreen API - Web APIs | MDN (mozilla.org),很多时候我们会轻视 MDN,但是圣经永远是圣经。
参考
- ::backdrop - CSS(层叠样式表) | MDN (mozilla.org)
- :fullscreen - CSS(层叠样式表) | MDN (mozilla.org)
- Document: fullscreenchange event - Web APIs | MDN (mozilla.org)
- Fullscreen API Standard (whatwg.org)
- Document.exitFullscreen()
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!