如何判断页面为全屏页面还是浏览器内部页面
https/localhtst环境
1、全屏事件的类别
浏览器存在两种全屏模式,两者对事件的处理逻辑完全不同:
全屏模式 | 触发方式 | 事件触发情况 | 控件显示情况 |
---|---|---|---|
网页级全屏 | 代码调用 requestFullscreen() | 会正常触发 fullscreenchange 事件 | 隐藏浏览器控件(地址栏、标签栏),但网页仍在浏览器上下文内 |
浏览器级全屏 | 按 F11 键 | 多数浏览器不触发 fullscreenchange 事件 | 完全隐藏浏览器所有控件,甚至隐藏浏览器边框(部分浏览器) |
F11
触发的是 “浏览器级全屏”,它属于浏览器自身的全局操作,而非网页发起的全屏请求,因此浏览器不会将其纳入网页可监听的 fullscreenchange
事件范畴。
由于需要使用F11
来进行全屏得切换,所以使用requestFullscreen()
会错过F11
全屏
2、解决方案
要捕获 F11
全屏,需放弃单一的 fullscreenchange
事件,改用 “窗口尺寸变化 + F11
按键捕获” 结合 的方案(兼容所有浏览器和环境),核心思路是:
-
案件捕获: 监听
keydown
事件,捕获F11键(e.key === 'F11') -
尺寸验证:监听
window.resize
事件,通过对比窗口尺寸与屏幕尺寸(window.innerWidth
接近screen.width
),确认是否进入全屏 -
状态对比: 用变量记录前后状态,判断是 “进入” 还是 “退出” F11 全屏。
<template><div class="f11-fullscreen-listener"><h1>F11 全屏修复版(支持原生 F11 全屏)</h1><p class="status" :class="isFullscreen ? 'full' : 'normal'">当前状态:{{ isFullscreen ? '全屏模式(F11/网页)' : '非全屏模式' }}</p><p class="tips">提示:按 F11 键或点击按钮测试全屏</p><button @click="toggleWebFullscreen" :disabled="isProcessing">{{ isProcessing ? '处理中...' : isFullscreen ? '退出网页全屏' : '进入网页全屏' }}</button><div class="log" ref="log"></div></div> </template> <script> export default {name: 'F11FixedFullscreen',data() {return {isFullscreen: false,isProcessing: false,screenWidth: screen.width,screenHeight: screen.height,resizeHandler: null,}},mounted() {// 1. 监听 F11 按键(捕获但不阻止默认行为)document.addEventListener('keydown', this.handleKeydown)// 2. 监听窗口尺寸变化(F11 全屏/退出会触发)this.resizeHandler = this.debounce(this.checkFullscreenBySize)window.addEventListener('resize', this.resizeHandler)// 3. 初始化状态检测this.checkFullscreenBySize()this.logEvent('监听已启动:按 F11 或点击按钮测试')},beforeDestroy() {// 移除监听,避免内存泄漏document.removeEventListener('keydown', this.handleKeydown)window.removeEventListener('resize', this.resizeHandler)},methods: {/*** 1. 捕获 F11 按键(仅监听,不阻止默认行为)*/handleKeydown(e) {if (e.key === 'F11') {// ✅ 移除 e.preventDefault(),允许 F11 触发原生全屏setTimeout(() => {this.checkFullscreenBySize() // 延迟检测,确保全屏状态已更新}, 300) // 延长到 300ms,适配不同浏览器的全屏生效速度}}, /*** 2. 通过尺寸判断全屏状态(F11 全屏/网页全屏通用)*/checkFullscreenBySize() {const windowW = window.innerWidthconst windowH = window.innerHeight// 全屏判断:窗口尺寸与屏幕尺寸差值 < 10px(允许微小误差)const newFullState = Math.abs(windowW - this.screenWidth) < 10 && Math.abs(windowH - this.screenHeight) < 10 if (newFullState !== this.isFullscreen) {const eventType = newFullState ? '进入' : '退出'this.isFullscreen = newFullStatethis.logEvent(`检测到${eventType}全屏(F11 或网页全屏)`)}}, /*** 3. 按钮触发网页级全屏(不影响 F11)*/toggleWebFullscreen() {if (this.isProcessing) returnthis.isProcessing = true try {if (this.isFullscreen) {// 退出网页级全屏if (document.exitFullscreen) {document.exitFullscreen().then(() => {this.checkFullscreenBySize()})}} else {// 进入网页级全屏const docEl = document.documentElementif (docEl.requestFullscreen) {docEl.requestFullscreen().then(() => {this.checkFullscreenBySize()})}}} catch (err) {this.logEvent(`操作失败:${err.message}`)} finally {this.isProcessing = false}}, /*** 防抖处理 resize 事件*/debounce(fn, delay = 150) {let timer = nullreturn () => {clearTimeout(timer)timer = setTimeout(fn, delay)}}, /*** 记录日志*/logEvent(msg) {const time = new Date().toLocaleTimeString()const logItem = document.createElement('p')logItem.textContent = `[${time}] ${msg}`this.$refs.log.appendChild(logItem)this.$refs.log.scrollTop = this.$refs.log.scrollHeight},}, } </script> <style scoped> .f11-fullscreen-listener {font-family: 'Segoe UI', Arial, sans-serif;min-height: 100vh;padding: 40px 20px;background-color: #f8fafc;box-sizing: border-box;color: #333; } h1 {text-align: center;color: #1e293b;margin: 0 0 20px;font-size: 24px; } .tips {text-align: center;color: #64748b;font-size: 14px;margin: 0 0 25px; } .status {text-align: center;font-size: 18px;padding: 14px;max-width: 500px;margin: 0 auto 20px;border-radius: 8px;background: white;box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);transition: all 0.3s; } .status.full {border-left: 4px solid #22c55e;color: #16a34a; } .status.normal {border-left: 4px solid #94a3b8;color: #475569; } button {display: block;margin: 0 auto 30px;padding: 10px 22px;font-size: 15px;color: white;background-color: #3b82f6;border: none;border-radius: 6px;cursor: pointer;transition: background 0.2s; } button:disabled {background-color: #93c5fd;cursor: not-allowed; } button:hover:not(:disabled) {background-color: #2563eb; } .log {max-width: 700px;margin: 0 auto;background: white;padding: 18px;border-radius: 8px;box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);max-height: 280px;overflow-y: auto; } .log p {margin: 7px 0;font-size: 14px;color: #555;line-height: 1.5; } /* 响应式适配 */ @media (max-width: 600px) {h1 {font-size: 20px;}.status,.log {padding: 12px;} } </style>
http环境
-
监听
window.resize
事件,通过对比window.innerWidth
与screen.width
、window.innerHeight
与screen.height
的差值判断是否全屏。
screen.height:物理显示器高度
window.innerHeight :浏览器内容显示区域高度
-
当尺寸从 “非接近屏幕” 变为 “接近屏幕” 时,判定为 “进入全屏”;反之则为 “退出全屏”。
<template><div class="http-fullscreen-switch"><h1>全屏切换监听(HTTP环境)</h1><p class="status">当前状态:{{ isFullscreen ? '全屏模式' : '非全屏模式' }}</p><div class="log" ref="log"><p>事件日志:</p></div><p class="tips">提示:按F11或调整窗口大小测试</p></div> </template> <script> export default {name: 'HttpFullscreenListener',data() {return {isFullscreen: false,screenWidth: screen.width, // 屏幕宽度(固定)screenHeight: screen.height, // 屏幕高度(固定)resizeHandler: null, // 防抖后的尺寸变化处理器}},mounted() {// 初始化状态this.isFullscreen = this.checkBySize()if (this.isFullscreen) {this.logEvent('初始状态:已处于全屏')} // 监听窗口尺寸变化(带防抖)this.resizeHandler = this.debounce(this.handleResize)window.addEventListener('resize', this.resizeHandler)this.logEvent('已启动HTTP环境全屏监听(基于窗口尺寸)')},beforeDestroy() {// 移除事件监听,避免内存泄漏window.removeEventListener('resize', this.resizeHandler)},methods: {/*** 通过窗口尺寸判断是否全屏*/checkBySize() {const windowWidth = window.innerWidthconst windowHeight = window.innerHeight // 全屏时窗口尺寸与屏幕尺寸的差值通常小于10px(允许微小误差)const widthDiff = Math.abs(windowWidth - this.screenWidth)const heightDiff = Math.abs(windowHeight - this.screenHeight) return widthDiff < 10 && heightDiff < 10}, /*** 处理窗口尺寸变化(核心:捕获全屏切换)*/handleResize() {const newState = this.checkBySize() // 状态变化时触发事件if (newState !== this.isFullscreen) {this.isFullscreen = newStateconst eventType = newState ? '进入全屏' : '退出全屏'this.logEvent(`检测到${eventType}(基于窗口尺寸变化)`)}}, /*** 防抖函数:避免频繁触发尺寸检测*/debounce(fn, delay = 100) {let timer = nullreturn () => {clearTimeout(timer)timer = setTimeout(fn, delay)}}, /*** 记录事件日志*/logEvent(message) {const time = new Date().toLocaleTimeString()const logItem = document.createElement('p')logItem.textContent = `[${time}] ${message}`this.$refs.log.appendChild(logItem)this.$refs.log.scrollTop = this.$refs.log.scrollHeight // 滚动到最新日志},}, } </script> <style scoped> .http-fullscreen-switch {font-family: 'Segoe UI', Arial, sans-serif;min-height: 100vh;padding: 40px 20px;background-color: #f8fafc;box-sizing: border-box;color: #333; } h1 {text-align: center;color: #1e293b;margin: 0 0 30px;font-weight: 600;font-size: 26px; } .status {text-align: center;font-size: 18px;padding: 16px 20px;margin: 0 auto 30px;max-width: 500px;border-radius: 8px;background-color: white;box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);border-left: 4px solid #3b82f6; /* 左侧蓝色标识线 */ } .log {max-width: 800px;margin: 0 auto 20px;background-color: white;border-radius: 8px;box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);padding: 20px;max-height: 300px;overflow-y: auto; } .log p {margin: 8px 0;font-size: 14px;color: #64748b;line-height: 1.5; } .log p:first-child {font-weight: 600;color: #1e293b;margin-bottom: 15px;padding-bottom: 8px;border-bottom: 1px solid #f1f5f9; } .tips {text-align: center;color: #64748b;font-size: 14px;margin: 0; } /* 响应式适配 */ @media (max-width: 600px) {h1 {font-size: 22px;}.status,.log {padding: 12px 15px;} } </style>