likes
comments
collection
share

前端JS-全屏总结

作者站长头像
站长
· 阅读数 58

前言

本以为调用一下api就能实现的全屏,但随着业务需求复杂度的提升,却花了一周的时间。而时隔半年,又出现了这个需求,本会让人叫苦连天,但结合之前的经验,一顿操作,那叫一个行云流水。不过确实也踩了不少的坑,这边做一个总结,希望看完对大家有所帮助。

JS全屏

说到全屏,我们脑海里的第一反应就是js原生方法:element.requestFullscreen(),以及与它经常一块儿 出现的几个方法

踩过的坑

如果你在做全屏需求时有以下几方面的困扰,本文章会为您解答相应技术方案

  1. 全屏后背景变黑
  2. 全屏后打开弹窗但弹窗在全屏下方
  3. 监听不了esc退出全屏事件
  4. 全屏代码优化

需求

我们先来看下需求:将一级弹窗内容全屏,全屏后点击某一项,需要打开二级弹窗

技术开发

这不很简单么,直接调用一下原生api是不是就好了,那我们来尝试一下: 代码:

  /** 全屏事件 */
  fullScreenModel(): void {
    const element = document.getElementById('ath-modal-id');
    /** 不同浏览器下需考虑兼容性问题*/
    if (element.requestFullscreen) {
      element.requestFullscreen();
    } else if (element['msRequestFullscreen']) {
      element['msRequestFullscreen']();
    } else if (element['mozRequestFullScreen']) {
      element['mozRequestFullScreen']();
    } else if (element['webkitRequestFullscreen']) {
      element['webkitRequestFullscreen']();
    }
    this.isFullScreen = true;
  }
  
   /** 退出全屏事件 */
  exitFullScreenModel(): void {
    if (document.exitFullscreen) {
      document.exitFullscreen();
    } else if (document['msExitFullscreen']) {
      document['msExitFullscreen']();
    } else if (document['mozCancelFullScreen']) {
      document['mozCancelFullScreen']();
    } else if (document['webkitExitFullscreen']) {
      document['webkitExitFullscreen']();
    }
    this.isFullScreen = false;
  }

代码写完了,我们全屏试一下:

全屏前:

前端JS-全屏总结 全屏后:

前端JS-全屏总结

黑色背景

原因

卧槽,我背景呢?咋黑了呢?咋办呢?一筹莫展的开始调研(百度谷歌)

找到的原因: stackoverflow.com/questions/1…

大概意思就是说浏览器默认背景色是黑色,我的内容其实是在的,只是是黑色背景的黑色内容,所以我看不见

前端JS-全屏总结 打开控制台试试看!

解决方案

前端JS-全屏总结 咦,页面元素还真的是在的,那简单,我们先尝试将全屏容器的背景换成白色 **

全屏时:
 this.render.setStyle(element, 'background-color', 'white');

退出全屏时:
this.render.removeStyle(document.getElementById('ath-modal-id'), 'background-color');

前端JS-全屏总结

那此时第一个bug就解决了,那我们再试一下此时能不能在全屏下打开弹窗:

全屏后打开弹窗但未显示

原因

我们会发现在全屏后点击销售部单号进行二级弹窗的打开是显示不了弹窗的,但退出全屏后发现弹窗实际上已经打开了

前端JS-全屏总结 做过前端的应该很快就能想到使用zindex增加对应层级不就行了么?

试了下没有任何作用。什么情况呢?我们回忆一下zindex的概念:当我们在定位元素上指定 z-index 时,它会创建一个堆叠上下文。

那什么是层叠上下文呢?具有共同父元素的元素组在堆叠顺序中一起向前或向后移动构成所谓的堆叠上下文。我们再去看angular的modal container是怎么做的?

前端JS-全屏总结

angular中每产生一个弹窗,就会将其放在cdk容器中,该容器与app-root也就是angular的根组件平级,而我们要全屏的内容嵌套在modal-mask的里面,嵌套非常深,那此时我们无论怎么添加层级都是不生效的,因为他们不属于一个层级,没有共同父元素。

那我们该怎么解决呢?不然得绩效减减啊,抓脑阔

解决方案

在一通花里胡哨的尝试后,还是很愁眉苦脸,突然灵感一闪,咦,那我能不能把根元素全屏呢?然后我把需要全屏的内容撑满页面不就好了么?我靠,我真是个小天才!

按照这个思路,写出如下代码:

  /** 全屏事件 */
  fullScreenModel(): void {
    const element = document.body;
    if (element.requestFullscreen) {
      element.requestFullscreen().then((): void => {
        this.render.addClass(document.getElementById('ath-modal-id'), 'full-screen');
      });
    } else if (element['msRequestFullscreen']) {
      element['msRequestFullscreen']();
    } else if (element['mozRequestFullScreen']) {
      element['mozRequestFullScreen']();
    } else if (element['webkitRequestFullscreen']) {
      element['webkitRequestFullscreen']();
    }
  }
  
   /** 退出全屏事件 */
  exitFullScreenModel(): void {
    if (document.exitFullscreen) {
      document.exitFullscreen().then((): void => {
        this.render.removeClass(document.getElementById('ath-modal-id'), 'full-screen');
      });
    } else if (document['msExitFullscreen']) {
      document['msExitFullscreen']();
    } else if (document['mozCancelFullScreen']) {
      document['mozCancelFullScreen']();
    } else if (document['webkitExitFullscreen']) {
      document['webkitExitFullscreen']();
    }
  }
.full-screen {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  width: 100vw;
  height: 100vh;
}

效果如下:

前端JS-全屏总结

前端JS-全屏总结

你以为此时就完了?这不得自测一手以防万一,于是又测出了bug

监听不了退出全屏事件

原因

我监听不了按esc的全屏退出啊,那就不能做对应的样式处理,那假如客户使用起来,页面不就错乱了?bug效果如下:

前端JS-全屏总结

emo了,一个简单的全屏遇见这么多问题,那就只能继续技术调研(百度),原因如下: stackoverflow.com/questions/7…

前端JS-全屏总结 简单来说就是chrome在按退出全屏按钮时触发不了按键事件,因此无论怎么监听都监听不了,那该怎么解决呢?

解决方案

其实链接上也给出了解决方案,大致意思就是在全屏状态下监听屏幕大小的变化即可:

前端JS-全屏总结

代码优化

全屏也是比较通用的场景,但目前代码比较混乱,有没有可以现成的工具包将对应的方法封装好,达到开箱即用的效果呢?

答案肯定是有的,使用方法自行查阅: www.npmjs.com/package/scr…

优化前:

  /** 全屏事件 */
  fullScreenModel(): void {
    const element = document.body;
    if (element.requestFullscreen) {
      element.requestFullscreen().then((): void => {
        this.render.addClass(document.getElementById('ath-modal-id'), 'full-screen');
        this.render.setStyle(document.querySelector('nz-modal-container'), 'background-color', 'white');
        // this.render.setStyle(element, 'background-color', 'white');
      });
    } else if (element['msRequestFullscreen']) {
      element['msRequestFullscreen']();
    } else if (element['mozRequestFullScreen']) {
      element['mozRequestFullScreen']();
    } else if (element['webkitRequestFullscreen']) {
      element['webkitRequestFullscreen']();
    }
  }

  /** 退出全屏事件 */
  exitFullScreenModel(): void {
    if (document.exitFullscreen) {
      document.exitFullscreen().then((): void => {
        this.render.removeClass(document.getElementById('ath-modal-id'), 'full-screen');
        this.render.removeStyle(document.querySelector('nz-modal-container'), 'background-color');
        // this.render.removeStyle(document.getElementById('ath-modal-id'), 'background-color');
      });
    } else if (document['msExitFullscreen']) {
      document['msExitFullscreen']();
    } else if (document['mozCancelFullScreen']) {
      document['mozCancelFullScreen']();
    } else if (document['webkitExitFullscreen']) {
      document['webkitExitFullscreen']();
    }
  }
  
 ngOnInit(): void {
    if (document.addEventListener) {
        document.addEventListener('webkitfullscreenchange', exitHandler, false);
        document.addEventListener('mozfullscreenchange', exitHandler, false);
        document.addEventListener('fullscreenchange', exitHandler, false);
        document.addEventListener('MSFullscreenChange', exitHandler, false);
    }
 }
 
 
exitHandler() {
    if (!document.webkitIsFullScreen && !document.mozFullScreen && !document.msFullscreenElement) {
        ... do something here
    }
}

优化后:

  /** 全屏事件 */
  fullScreenModel(): void {
    screenfull.request(document.body);
    this.render.addClass(document.getElementById('ath-modal-id'), 'full-screen');
    this.render.setStyle(document.querySelector('nz-modal-container'), 'background-color', 'white');
  }

  /** 退出全屏事件 */
  exitFullScreenModel(): void {
    this.render.removeClass(document.getElementById('ath-modal-id'), 'full-screen');
    this.render.removeStyle(document.querySelector('nz-modal-container'), 'background-color');
    screenfull.exit();
  }
  
   ngOnInit(): void {
    screenfull.on('change', () => {
      this.exitHandler();
    });
   }

  exitHandler() {
    const element = document.getElementById('ath-modal-id');
    if (!screenfull.isFullscreen) {
      this.render.removeStyle(element, 'overflow');
      this.render.removeStyle(document.querySelector('nz-modal-container'), 'background-color');
    }
  }

总结

全屏需要考虑的点可能还不止这些,但此次研发仅凭以上内容,确实能收获一些东西,希望看完的小伙伴也能有所收获!!!但行好事,莫问前程。

转载自:https://juejin.cn/post/7251415042742321212
评论
请登录