1、项目背景:新bug又出现
即前两天出现 十年全栈,8个小时解决z-index不生效问题 后又出现了神奇问题,近期 《高质量代码的项目:SmartAdmin》 有人反馈 table 局部全屏下,第二个Modal弹窗,会被第一个Drawer抽题遮挡,如下图,经排查,也不是 z-index
问题,最终祭出一个终极解决方案,能彻底解决各类局部全屏情况下的弹窗遮挡等问题。
2、需求与实现:很经典的一个需求场景
需求:
项目是是需要表格table
有个全屏操作的按钮,点击会将表格进行全屏,如下图;
代码实现:
代码使用的是浏览器自带的方法,将 table
的 dom
元素根据浏览器类型,进行全屏操作,伪代码如下:
let contentElement = document.getElementById("smartAdminContent");
contentElement.requestFullscreen();
element.webkitRequestFullScreen();
....
3、Bug复现
非全屏模式下,第一步Drawer抽屉
,然后第二步弹出Modal
是没有问题的;
但是全屏模式下,会出现各种弹窗的问题,如:Modal
不显示、下拉框a-select
不显示等等各类问题;真可谓是神奇!
感兴趣的大佬可以写一个小demo试试。
4、尝试解决思路1:z-index问题
即前两天出现 十年全栈,8个小时解决z-index不生效问题 后彻底了解了z-index
层级问题的知识后,反应应该是此问题,于是开启z-index
排查,发现还真是 z-index
,我一修改z-index
数值大小就好了。直接修改代码,调整z-index
如下:
一切顺利,但是 a-select
又不显示了,难不成都要改一遍z-index
?疯了吗?
5、尝试解决思路2:上网查
网上总结下几个解决方案:
方案1:
修改getContainer
,改为 body
或者全屏元素
,如下代码;结论:不可用,不可能每个组件都改一下,太麻烦了。
message.config({
maxCount: 3,
getContainer:() => document.getElementById('thisPage') || document.body //父组件元素ID
})
方案2:
改变挂载对象。挂到根节点上:document.documentElement,再使用定位fixed目标元素,改变z-index
;
- 问题:
position: fixed
滚动条无法滚动; - 原因:
position:fixed
相对于视口viewport
的定位,元素在屏幕滚动时不会发生改变; - 解决方案:当元素祖先的
transform, perspective
或filter
属性非none
时,容器由视口改为该祖先。同时给祖先元素设置一个transform: scale(1)
属性。
结论都好复杂,且不容易理解。
6、尝试解决思路3:终极解决方案
根据以上方案带来的思路,发现所有的矛盾点都指向了 局部元素 全屏,因为局部元素 全屏的优先级要比 body
要高,但是所有 Modal
、Message
等又都是挂载到到body
上,那么冲突就来了,根本解决不了,于是换了一个思路豁然开朗了;
既然矛盾都出在了body
上,那么我就直接将body
全屏不就可以了,和之前非全屏一样,Modal
、Message
等挂载到到body
上就没有问题了。
模型如下:非全屏的元素全屏的时候都隐藏,然后全屏元素铺满body,全屏body即可。
代码如下:
7、局部全屏总结
在使用 ant design vue
或者element plus
等类似UI框架都会出现这个局部全屏
,弹出框或者抽屉等等被遮挡的情况,原理呢如上述第6点,放弃z-index
解决思路,直接从body
下手,从根本上解决问题:
全屏时:
- 1)非全屏其他元素 全部隐藏
- 2)修改定位,将全屏元素充满body
- 3)将body全屏
退出全屏时:
- 1)非全屏其他元素 全部显示
- 2)修改定位,将全屏元素恢复之前
- 3)取消body全屏
其他注意事项:
- 隐藏可以使用
vue
的v-show
- 跨组件的标识可以使用
pinia
存储全屏状态
8、感想
一个十年全栈再次被局部全屏
浪费了摸鱼时间的8小时,又应了那句话“活到老,写到老”。
感谢文章引用: