前端全屏显示解决方案分享

embedded/2024/11/20 16:06:00/

本文分享的内容是前端全屏显示的解决方案,来源于103项目中的需求。主要是将开发过程中遇到问题,解决问题的思路分享出来,对于后面遇到相同的业务场景时可以借鉴一下,提高我们的开发效率,少走一些弯路。

需求背景
  • 用户需要针对车辆的行驶路径与收费路径以及拆分路径中的费用进行比对分析,由于交互设计问题导致用户无法同时比对较多的数据,如下图:

    在这里插入图片描述

  • 用户在门架流水中需要操作门架数据进行二次计算,同样是交互设计问题无法给到用户较大的操作空间,如下图:

    在这里插入图片描述

基于以上的需求,需要前端在项目中加入全屏按钮,便于给到用户较大的空间进行比对和操作,那么下面就将给出在开发过程中我用到的解决方案,以及方案的可行性。

  1. 使用 requestFullscreenexitFullscreen API

    通过浏览器的全屏 API(Fullscreen API)来控制页面或某个元素进入或退出全屏模式。这也是最开始我才用的方案,具体的代码实现如下:

    <template>......<divclass="tab":class="{ 'fullscreen-tab': isFullscreen }"id="analysis-tab">......</div>...
    </template><script lang='ts'>
    export default defineComponent({setup(props) {......;const isFullscreen = ref(false);const toggleFullscreen = () => {const elem = document.getElementById("analysis-tab");if (!document.fullscreenElement) {isFullscreen.value = true;if (elem.requestFullscreen) {elem.requestFullscreen();}} else {isFullscreen.value = false;if (document.exitFullscreen) {document.exitFullscreen();}}};const handleFullscreenChange = () => {isFullscreen.value = !!document.fullscreenElement;};onMounted(() => {// 监听键盘事件document.addEventListener("fullscreenchange",handleFullscreenChange);document.addEventListener("webkitfullscreenchange",handleFullscreenChange);document.addEventListener("mozfullscreenchange",handleFullscreenChange);document.addEventListener("MSFullscreenChange",handleFullscreenChange);getFeeBasicInfo(props.transId, props.transDate);});onBeforeUnmount(() => {// 移除事件监听document.removeEventListener("fullscreenchange",handleFullscreenChange);document.removeEventListener("webkitfullscreenchange",handleFullscreenChange);document.removeEventListener("mozfullscreenchange",handleFullscreenChange);document.removeEventListener("MSFullscreenChange",handleFullscreenChange);});return {...,isFullscreen,toggleFullscreen,}}
    });
    </script>
    

    这种解决方案是大部分前端首先能够想到的,那么这种方案并不是适用大多数场景,对于仅仅需要全屏展示的业务场景来说是可以满足的,但是遇到目标元素全屏后,内部有其他的操作:点击按钮展示弹窗、数据的增删改查等,这些需求是不能满足的。

    比如103中的需求,用户点击全屏按钮后,目标元素全屏展示;用户点击新增门架,此时会有一个弹窗展示,但是实际情况是弹窗元素已经在body元素中出现,但是在页面中无法显示。如下图:

在这里插入图片描述

原因是:浏览器在全屏模式下通常会屏蔽掉一些页面交互和 UI 元素,以减少干扰。当你进入全屏模式时,requestFullscreen 会把目标元素的 z-index 设置为较高,可能会导致其他弹窗无法显示在其之上。因为全屏模式本质上覆盖了整个视口,导致无法正常显示任何其他 UI 元素。

这里需要注意的是:修改层级z-index是没有用的,仍然不能在全屏之后展示弹窗,如下图所示:

在这里插入图片描述

所以在第一版开发的时候,通过变量判断是否进入全屏模式,全屏模式下禁用按钮的点击操作,后续用户要求既要能够全屏展示,同时能够进行其他操作。

  1. 封装全屏组件

    应用户需求,调整方案,我想到的是封装全屏组件,就是类似于UI库的弹窗组件,当用户点击全屏按钮时,显示全屏弹窗组件。这样做看起来也是满足需求的,同时也可以解决前面描述的问题,具体实现步骤如下:

    • 将需要全屏的内容封装成组件,进行复用

    • 引入全屏组件,代码如下:

      <div class="tab__div_height-600"><tab-analysisref="tatbAnalysisRef":activeName="activeName":feeBasicInfo="feeBasicInfo":isFullscreen="tabAnalysisStatus"@updateActiveName="updateActiveName"@updateTabAnalysisStatus="updateTabAnalysisStatus"/>
      </div>
      ......  
      <c-full-screen v-model="tabAnalysisStatus" :close-btn-status="false"><tab-analysisref="tatbAnalysisRef":activeName="activeName":feeBasicInfo="feeBasicInfo":isFullscreen="tabAnalysisStatus"@updateActiveName="updateActiveName"@updateTabAnalysisStatus="updateTabAnalysisStatus"/>
      </c-full-screen>
      
      <!--@author: duanfc@time: 2024-11-15 15:40:00@description: 全屏弹窗组件@path: /@lastChange: duanfc
      --><template><transition name="fade"><divv-if="visible"class="fullscreen-dialog-overlay"@click.self="close"><div class="fullscreen-dialog-content"><buttonclass="fullscreen-dialog-close"@click="close"v-if="closeBtnStatus">×</button><div class="fullscreen-dialog-body"><slot></slot></div></div></div></transition>
      </template><script>
      export default {name: "fullScreenDialog",components: {},props: {value: {type: Boolean,default: false,},closeBtnStatus: {type: Boolean,default: true,},},data() {return {visible: this.value,};},watch: {value(newVal) {this.visible = newVal;if (newVal) {document.body.appendChild(this.$el);}},},computed: {},methods: {close() {this.visible = false;this.$emit("input", false); // 双向绑定},},created() {},mounted() {if (this.visible) {document.body.appendChild(this.$el);}},destroyed() {if (this.$el && this.$el.parentNode) {this.$el.parentNode.removeChild(this.$el);}}
      };
      </script><style scoped>
      .fullscreen-dialog-overlay {position: fixed;top: 0;left: 0;width: 100vw;height: 100vh;background: rgba(0, 0, 0, 0.3);display: flex;justify-content: center;align-items: center;z-index: 9999;
      }
      .fullscreen-dialog-content {position: relative;width: 100%;height: 100%;background: white;overflow: auto;display: flex;flex-direction: column;
      }.fullscreen-dialog-close {position: absolute;top: 20px;right: 20px;background: none;border: none;font-size: 30px;color: #333;cursor: pointer;
      }.fullscreen-dialog-body {flex-grow: 1;padding: 16px 24px;overflow-y: auto;
      }
      .fade-enter-active,
      .fade-leave-active {transition: opacity 0.5s ease-in-out;
      }.fade-enter,
      .fade-leave-to {opacity: 0;
      }
      </style>
      

      tab-analysis组件是需要比对的模块,封装为组件,在c-full-screen全屏组件中二次复用。看起来写法没有问题,但是会有一个问题,就是全屏操作无法是没有记忆功能的:当用户现在页面中进行操作,然后中途点击全屏按钮,此时的弹窗中是不能记录到先前的用户操作,是一个初始的内容。如下:

      在这里插入图片描述

      当然了,如果较真非要通过这种方式实现用户需求,也许可以实现,但是对于前端来说处理的逻辑太多,复杂性也比较高;对于门架的全屏需求使用这种方式是比较符合的,因为内部操作较少,便于对数据进行控制,综合评估还是不推荐采用此方式。

    1. CSS的position属性

      在 CSS 中,position: fixed 是一种常见的布局方式,用于将元素定位到浏览器窗口的固定位置,而不随着页面的滚动而移动。固定定位使元素始终保持在视口内,不管页面滚动与否。这个方案是从上面的方法中衍生出来的,通过position: fixed将需要全屏的内容脱离文档流,然后通过z-index控制层级,就可以完美解决我们的问题。

      具体步骤如下:

      • 将需要全屏展示的组件及其父元素设置id属性
      • 通过原生js操作DOM的方式,动态修改目标元素的css属性,移动DOM

      代码如下:

      <divclass="rate-visualization"v-loading="loading"element-loading-text="加载中...":element-loading-spinner="$loadingStyle"id="rate-visualization"
      ><!-- 收费基础信息 -->.....<divclass="tab":class="{ 'fullscreen-tab': isFullscreen }"id="analysis-tab"><!-- 全屏模块 --></div>
      </div>const isFullscreen = ref(false);
      const toggleFullscreen = () => {const elem = document.getElementById("analysis-tab");if (!isFullscreen.value) {isFullscreen.value = true;document.body.appendChild(elem);} else {isFullscreen.value = false;const parent = document.getElementById("rate-visualization");const children = parent.children;parent.insertBefore(elem, children[1]);}
      };<style lang="less">
      .fullscreen-tab {height: 100%;width: 100%;position: fixed;top: 0;left: 0;z-index: 999;background-color: #fff;.tab {height: 100%;width: 100%;padding-top: 6px;position: relative;.el-tabs__header {// margin: 0;padding-top: 6px;.el-tabs__nav-scroll {padding-left: 10px;.el-tabs__nav {border: none !important;.el-tabs__item {border: none !important;color: #409eff;&.is-active {background: linear-gradient(180deg,#83a0fd 0%,#2552dd 100%);border-radius: 10px 10px 0px 0px;color: #fff;}}}}}.el-tabs__content {height: calc(100% - 56px);padding: 0 20px 20px;.el-tab-pane {height: 100%;}}}.change-compare-mode {position: absolute;right: 50px;top: 12px;width: 106px;height: 32px;line-height: 32px;}.el-icon-full-screen {font-size: 20px;margin-top: 11px;margin-left: 8px;cursor: pointer;position: absolute;top: 8px;right: 20px;}.exit-fullscreen {height: 24px;width: 24px;margin-top: 9px;margin-left: 8px;cursor: pointer;position: absolute;top: 8px;right: 20px;}
      }
      </style>
      
      1. 当用户点击全屏时,动态设置position: fixed脱离文档流,设置全屏展示
      2. 点击取消展示时,移除position: fixed属性,同时需要将该元素移动到原来的位置

      [!CAUTION]

      需要注意的是样式设置,由于全屏后脱离文档流,因此属性需要全局设置,要保证样式的唯一性,避免被影响

      完整效果如下:
      在这里插入图片描述

      总结

      三种方案适用的场景是不一样的,前两种方案的适用性需要根据业务需求具体情况具体分析,不能兼容所有场景;第三种方案是相对来说适用性较强的,也有不足之处,就是动态控制DOM会造成重绘,对于性能会有一点影响。从复杂性和实用性考虑,首选方案3


http://www.ppmy.cn/embedded/139116.html

相关文章

单片机的基本组成与工作原理

单片机&#xff08;Microcontroller Unit, MCU&#xff09;是一种将计算机的主要部分集成在一个芯片上的小型计算机系统。它通常包括中央处理器&#xff08;CPU&#xff09;、存储器&#xff08;Memory&#xff09;、输入输出接口&#xff08;I/O Ports&#xff09;、定时器/计…

【UGUI】Unity 游戏开发:背包系统初始化克隆道具

在游戏开发中&#xff0c;背包系统是一个非常常见的功能模块。它允许玩家收集、管理和使用各种道具。今天&#xff0c;我们将通过一个简单的示例来学习如何在 Unity 中初始化一个背包系统。我们将使用 Unity 2021.3.7 版本&#xff0c;并结合 C# 脚本来实现这一功能。 1. 场景…

PH热榜 | 2024-11-19

DevNow 是一个精简的开源技术博客项目模版&#xff0c;支持 Vercel 一键部署&#xff0c;支持评论、搜索等功能&#xff0c;欢迎大家体验。 在线预览 1. Layer 标语&#xff1a;受大脑启发的规划器 介绍&#xff1a;体验一下这款新一代的任务和项目管理系统吧&#xff01;它…

25. 架构能力

文章目录 第25章 架构能力25.1 个人能力&#xff1a;架构师的职责、技能和知识职责技能知识那经验方面呢&#xff1f; 25.2 软件架构组织的能力25.3 成为更优秀的架构师接受指导指导他人 25.4 小结25.5 扩展阅读25.6 问题讨论 第25章 架构能力 人生苦短&#xff0c;学海无涯。 …

借助Excel实现Word表格快速排序

实例需求&#xff1a;Word中的表格如下图所示&#xff0c;为了强化记忆&#xff0c;希望能够将表格内容随机排序&#xff0c;表格第一列仍然按照顺序编号&#xff0c;即编号不跟随表格行内容调整。 乱序之后的效果如下图所示&#xff08;每次运行代码的结果都不一定相同&#x…

如何在 Python 中判断 ADB 设备是否连接

在进行 Android 自动化测试时,使用 ADB (Android Debug Bridge) 与设备进行交互是常见的做法。通常我们需要确认 ADB 是否连接到设备,然后才能执行后续的测试操作。本文将介绍如何在 Python 中检查 adb devices 命令的输出,判断是否有设备连接。 1. 什么是 adb devices 命令…

ftdi_sio应用学习笔记 1 - 查找串口

目录 1. 打开文件夹"/sys/bus/usb/devices/" 2. 遍历所有USB文件夹 3. 通过VID判断是否为FTDI设备 4. 创建设备链 5. 获取其他属性 6. 遍历接口文件夹 7. 释放资源 PS&#xff1a;源代码在&#xff1a;ftdi_sio: 基于标准的ftdi_sio&#xff0c;增加MPSSE功能…

如何挑选路由器?需要看哪些参数?

挑选路由器时&#xff0c;选择合适的型号和参数对于确保家庭或办公网络的速度、稳定性和覆盖范围至关重要。以下是挑选路由器时需要考虑的关键参数和因素&#xff1a; 1. 无线标准 (Wi-Fi标准) 无线标准是衡量路由器性能的核心指标。不同的无线标准提供不同的速率、范围和技术…