前端全屏顯示解決方案分享(附圖文詳解)
前言
本文分享的內(nèi)容是前端全屏顯示的解決方案,來源于103項目中的需求。主要是將開發(fā)過程中遇到問題,解決問題的思路分享出來,對于后面遇到相同的業(yè)務(wù)場景時可以借鑒一下,提高我們的開發(fā)效率,少走一些彎路。
需求背景
用戶需要針對車輛的行駛路徑與收費路徑以及拆分路徑中的費用進行比對分析,由于交互設(shè)計問題導(dǎo)致用戶無法同時比對較多的數(shù)據(jù),如下圖:

用戶在門架流水中需要操作門架數(shù)據(jù)進行二次計算,同樣是交互設(shè)計問題無法給到用戶較大的操作空間,如下圖:

基于以上的需求,需要前端在項目中加入全屏按鈕,便于給到用戶較大的空間進行比對和操作,那么下面就將給出在開發(fā)過程中我用到的解決方案,以及方案的可行性。
使用 requestFullscreen 和 exitFullscreen API
通過瀏覽器的全屏 API(Fullscreen API)來控制頁面或某個元素進入或退出全屏模式。這也是最開始我才用的方案,具體的代碼實現(xiàn)如下:
<template>
......
<div
class="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(() => {
// 監(jiān)聽鍵盤事件
document.addEventListener(
"fullscreenchange",
handleFullscreenChange
);
document.addEventListener(
"webkitfullscreenchange",
handleFullscreenChange
);
document.addEventListener(
"mozfullscreenchange",
handleFullscreenChange
);
document.addEventListener(
"MSFullscreenChange",
handleFullscreenChange
);
getFeeBasicInfo(props.transId, props.transDate);
});
onBeforeUnmount(() => {
// 移除事件監(jiān)聽
document.removeEventListener(
"fullscreenchange",
handleFullscreenChange
);
document.removeEventListener(
"webkitfullscreenchange",
handleFullscreenChange
);
document.removeEventListener(
"mozfullscreenchange",
handleFullscreenChange
);
document.removeEventListener(
"MSFullscreenChange",
handleFullscreenChange
);
});
return {
...,
isFullscreen,
toggleFullscreen,
}
}
});
</script>
這種解決方案是大部分前端首先能夠想到的,那么這種方案并不是適用大多數(shù)場景,對于僅僅需要全屏展示的業(yè)務(wù)場景來說是可以滿足的,但是遇到目標元素全屏后,內(nèi)部有其他的操作:點擊按鈕展示彈窗、數(shù)據(jù)的增刪改查等,這些需求是不能滿足的。
比如103中的需求,用戶點擊全屏按鈕后,目標元素全屏展示;用戶點擊新增門架,此時會有一個彈窗展示,但是實際情況是彈窗元素已經(jīng)在body元素中出現(xiàn),但是在頁面中無法顯示。如下圖:

原因是:瀏覽器在全屏模式下通常會屏蔽掉一些頁面交互和 UI 元素,以減少干擾。當你進入全屏模式時,requestFullscreen 會把目標元素的 z-index 設(shè)置為較高,可能會導(dǎo)致其他彈窗無法顯示在其之上。因為全屏模式本質(zhì)上覆蓋了整個視口,導(dǎo)致無法正常顯示任何其他 UI 元素。
這里需要注意的是:修改層級z-index是沒有用的,仍然不能在全屏之后展示彈窗,如下圖所示:

所以在第一版開發(fā)的時候,通過變量判斷是否進入全屏模式,全屏模式下禁用按鈕的點擊操作,后續(xù)用戶要求既要能夠全屏展示,同時能夠進行其他操作。
封裝全屏組件
應(yīng)用戶需求,調(diào)整方案,我想到的是封裝全屏組件,就是類似于UI庫的彈窗組件,當用戶點擊全屏按鈕時,顯示全屏彈窗組件。這樣做看起來也是滿足需求的,同時也可以解決前面描述的問題,具體實現(xiàn)步驟如下:
CSS的position屬性
在 CSS 中,position: fixed 是一種常見的布局方式,用于將元素定位到瀏覽器窗口的固定位置,而不隨著頁面的滾動而移動。固定定位使元素始終保持在視口內(nèi),不管頁面滾動與否。這個方案是從上面的方法中衍生出來的,通過position: fixed將需要全屏的內(nèi)容脫離文檔流,然后通過z-index控制層級,就可以完美解決我們的問題。
具體步驟如下:
代碼如下:
<div
class="rate-visualization"
v-loading="loading"
element-loading-text="加載中..."
:element-loading-spinner="$loadingStyle"
id="rate-visualization"
>
<!-- 收費基礎(chǔ)信息 -->
.....
<div
class="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>
當用戶點擊全屏?xí)r,動態(tài)設(shè)置position: fixed脫離文檔流,設(shè)置全屏展示
點擊取消展示時,移除position: fixed屬性,同時需要將該元素移動到原來的位置
[!CAUTION]
需要注意的是樣式設(shè)置,由于全屏后脫離文檔流,因此屬性需要全局設(shè)置,要保證樣式的唯一性,避免被影響
完整效果如下:

總結(jié)
三種方案適用的場景是不一樣的,前兩種方案的適用性需要根據(jù)業(yè)務(wù)需求具體情況具體分析,不能兼容所有場景;第三種方案是相對來說適用性較強的,也有不足之處,就是動態(tài)控制DOM會造成重繪,對于性能會有一點影響。從復(fù)雜性和實用性考慮,首選方案3
將需要全屏的內(nèi)容封裝成組件,進行復(fù)用
引入全屏組件,代碼如下:
<div class="tab__div_height-600"> <tab-analysis ref="tatbAnalysisRef" :activeName="activeName" :feeBasicInfo="feeBasicInfo" :isFullscreen="tabAnalysisStatus" @updateActiveName="updateActiveName" @updateTabAnalysisStatus="updateTabAnalysisStatus" /> </div> ...... <c-full-screen v-model="tabAnalysisStatus" :close-btn-status="false"> <tab-analysis ref="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"> <div v-if="visible" class="fullscreen-dialog-overlay" @click.self="close" > <div class="fullscreen-dialog-content"> <button class="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全屏組件中二次復(fù)用??雌饋韺懛]有問題,但是會有一個問題,就是全屏操作無法是沒有記憶功能的:當用戶現(xiàn)在頁面中進行操作,然后中途點擊全屏按鈕,此時的彈窗中是不能記錄到先前的用戶操作,是一個初始的內(nèi)容。如下:
當然了,如果較真非要通過這種方式實現(xiàn)用戶需求,也許可以實現(xiàn),但是對于前端來說處理的邏輯太多,復(fù)雜性也比較高;對于門架的全屏需求使用這種方式是比較符合的,因為內(nèi)部操作較少,便于對數(shù)據(jù)進行控制,綜合評估還是不推薦采用此方式。
- 將需要全屏展示的組件及其父元素設(shè)置
id屬性 - 通過
原生js操作DOM的方式,動態(tài)修改目標元素的css屬性,移動DOM
到此這篇關(guān)于前端全屏顯示解決方案的文章就介紹到這了,更多相關(guān)前端全屏顯示解決內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue three.js創(chuàng)建地面并設(shè)置陰影實現(xiàn)示例
這篇文章主要為大家介紹了vue three.js創(chuàng)建地面并設(shè)置陰影實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
安裝@vue/cli 報錯npm WARN deprecated request
這篇文章主要介紹了安裝@vue/cli 報錯npm WARN deprecated request@2.88.2問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03
Vue數(shù)據(jù)代理的實現(xiàn)流程逐步講解
通過一個對象代理對另一個對象中的屬性的操作(讀/寫),就是數(shù)據(jù)代理。要搞懂Vue數(shù)據(jù)代理這個概念,那我們就要從Object.defineProperty()入手,Object.defineProperty()是Vue中比較底層的一個方法,在數(shù)據(jù)劫持,數(shù)據(jù)代理以及計算屬性等地方都或多或少的用到了本函數(shù)2023-01-01
vue項目fetch本地PAG格式文件404 NotFound的解決
這篇文章主要介紹了vue項目fetch本地PAG格式文件404 NotFound的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
elementui 日期選擇器el-date-picker如何給指定日期添加圓點標注
這篇文章主要介紹了elementui 日期選擇器el-date-picker如何給指定日期添加圓點標注,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2024-07-07

