ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

可视化大屏全屏功能实战:Fullscreen API与ECharts自适应全解析

可视化大屏全屏功能实战:Fullscreen API与ECharts自适应全解析

可视化大屏的全屏功能,看起来是个小需求,但真正做过大屏项目的人都知道,这里面藏着一堆让人抓狂的细节。我最近刚交付了一个数据可视化大屏项目,全屏这块踩了不少坑,今天就把整个实现过程完整拆解一遍,从浏览器原生Fullscreen API的使用,到全屏后ECharts图表的自适应处理,再到各种浏览器兼容性和交互细节,全部讲透。

这篇文章适合正在做大屏项目的开发者,尤其是那些刚接触可视化大屏、对全屏功能实现还没有完整思路的朋友。如果你已经做过几个大屏项目但全屏这块总是出bug,这篇文章也能帮你补齐盲区。我会从最基础的原生API讲起,逐步深入到图表自适应、多组件联动、异常处理等实战细节,每个环节都附上可直接复用的代码。

1. 为什么大屏项目不能只靠CSS做全屏

很多人第一反应是:全屏不就是把容器宽高设成100vw和100vh吗?这个思路在普通页面上勉强能用,但在可视化大屏场景下问题很多。

1.1 CSS伪全屏的三个致命缺陷

第一个缺陷是浏览器UI无法隐藏。你用CSS把容器撑满视口,但浏览器的地址栏、标签栏、书签栏依然占着屏幕空间。大屏项目通常是要投到会议室大屏或者LED拼接屏上展示的,这些浏览器UI会直接破坏沉浸感。尤其是演示场景下,领导看到地址栏露出来,体验直接打折扣。

第二个缺陷是F11和CSS全屏不等价。用户按F11进入的是浏览器级别的全屏,这时候你的页面确实占满了整个屏幕,但问题是:你无法通过JavaScript监听F11的按下事件,也无法在F11全屏状态下控制页面行为。更麻烦的是,F11全屏和代码触发的全屏是两套独立的状态,用户按了F11之后,你再调用代码全屏,可能会出现状态混乱。

第三个缺陷是ESC键行为不可控。CSS伪全屏下,用户按ESC没有任何反应,因为压根没进入真正的全屏状态。但如果你用了Fullscreen API,ESC会退出全屏,这时候你需要监听全屏变化事件来同步UI状态。如果只靠CSS,你连这个事件都拿不到。

// 错误示范:纯CSS伪全屏 // 这种方式无法隐藏浏览器UI,也无法监听ESC退出 .dashboard-container { width: 100vw; height: 100vh; overflow: hidden; }

1.2 Fullscreen API的核心优势

Fullscreen API是浏览器原生提供的全屏接口,它能让指定元素真正占据整个屏幕,隐藏所有浏览器UI。核心方法就几个:

  • element.requestFullscreen():让某个元素进入全屏
  • document.exitFullscreen():退出全屏
  • document.fullscreenElement:获取当前全屏的元素
  • document.fullscreenEnabled:判断当前环境是否支持全屏

这几个API看起来简单,但实际用起来有不少门道。比如requestFullscreen()返回的是Promise,在有些浏览器里如果不处理rejection,会静默失败。再比如fullscreenElement在跨浏览器时前缀不一致,需要做兼容处理。

注意:Fullscreen API必须由用户交互事件(如click、keydown)触发,不能在页面加载时自动调用,否则浏览器会拦截并报错。这是浏览器的安全策略,没有绕过的方法。

1.3 全屏方案选型对比

方案能否隐藏浏览器UI能否监听ESC兼容性适用场景
CSS伪全屏否否全部普通页面布局
Fullscreen API是是IE11+大屏演示
F11浏览器全屏是否全部用户手动操作
Electron全屏是是仅桌面端桌面应用

从表格可以清楚看出,如果是Web端的大屏项目,Fullscreen API是唯一能同时满足隐藏UI和监听状态变化的方案。如果是Electron打包的桌面应用,可以直接用Electron的setFullScreen方法,更稳定。

2. Fullscreen API的兼容性处理与封装

原生API在不同浏览器下的表现差异不小,直接裸用很容易出问题。我建议做一层封装,把兼容性细节都吃掉。

2.1 浏览器前缀的坑

虽然现在主流浏览器基本都支持标准API了,但如果你需要兼容一些老版本浏览器,前缀还是得处理。常见的后缀有:

  • 标准:requestFullscreen、exitFullscreen、fullscreenElement
  • WebKit:webkitRequestFullscreen、webkitExitFullscreen、webkitFullscreenElement
  • Firefox:mozRequestFullScreen、mozCancelFullScreen、mozFullScreenElement
  • IE11:msRequestFullscreen、msExitFullscreen、msFullscreenElement

注意Firefox的大小写有点特殊,是mozRequestFullScreen,Screen的S是大写。这个细节很容易写错,写错了在Firefox下就静默失败。

// 全屏API兼容性封装 const FullscreenHelper = { // 获取当前全屏元素 getFullscreenElement() { return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null; }, // 请求全屏 requestFullscreen(element) { const el = element || document.documentElement; const requestMethod = el.requestFullscreen || el.webkitRequestFullscreen || el.mozRequestFullScreen || el.msRequestFullscreen; if (requestMethod) { // 注意:requestFullscreen返回Promise,需要catch const result = requestMethod.call(el); if (result && result.catch) { result.catch((err) => { console.warn('全屏请求失败:', err.message); }); } return true; } console.warn('当前浏览器不支持全屏API'); return false; }, // 退出全屏 exitFullscreen() { const exitMethod = document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen; if (exitMethod) { const result = exitMethod.call(document); if (result && result.catch) { result.catch((err) => { console.warn('退出全屏失败:', err.message); }); } } }, // 监听全屏变化 onFullscreenChange(callback) { const events = [ 'fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange' ]; events.forEach(eventName => { document.addEventListener(eventName, callback); }); }, // 判断是否支持全屏 isSupported() { return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled); } };

2.2 requestFullscreen的Promise陷阱

标准API的requestFullscreen()返回的是一个Promise,但很多老版本浏览器返回的是undefined。如果你直接.catch(),在老浏览器上会报"Cannot read property 'catch' of undefined"。所以上面代码里我先判断了result && result.catch,这样才稳妥。

另外,Promise的rejection一定要处理。常见的rejection原因有:

  • 不是用户交互触发(比如在setTimeout里调用)
  • 元素被隐藏或不可见
  • 浏览器策略限制(比如iframe没有allowfullscreen属性)
  • 用户拒绝了全屏请求

如果不catch,这些错误会静默吞掉,你调试的时候会一脸懵。

2.3 全屏状态同步的完整逻辑

全屏状态变化时,你需要同步更新UI,比如切换按钮图标、调整布局、触发图表resize。这里的关键是监听fullscreenchange事件,而不是在调用requestFullscreen之后直接改状态。因为用户可能按ESC退出,也可能按F11切换,这些操作都会触发fullscreenchange。

// Vue3组合式API中的全屏状态管理 import { ref, onMounted, onUnmounted } from 'vue'; export function useFullscreen(targetRef) { const isFullscreen = ref(false); const handleFullscreenChange = () => { isFullscreen.value = !!FullscreenHelper.getFullscreenElement(); // 全屏状态变化后,延迟触发图表resize // 延迟是因为浏览器全屏动画需要时间,立即resize尺寸可能不准 setTimeout(() => { window.dispatchEvent(new Event('resize')); }, 300); }; const toggleFullscreen = () => { if (isFullscreen.value) { FullscreenHelper.exitFullscreen(); } else { const el = targetRef.value || document.documentElement; FullscreenHelper.requestFullscreen(el); } }; onMounted(() => { FullscreenHelper.onFullscreenChange(handleFullscreenChange); }); onUnmounted(() => { // 组件销毁时移除监听,防止内存泄漏 const events = [ 'fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange' ]; events.forEach(eventName => { document.removeEventListener(eventName, handleFullscreenChange); }); }); return { isFullscreen, toggleFullscreen }; }

这段代码里有个细节值得说:全屏变化后我延迟了300ms才触发resize。原因是浏览器进入全屏有一个动画过程,在动画过程中元素的尺寸是渐变的,如果你立即resize,图表拿到的尺寸可能还是旧尺寸。延迟300ms后,全屏动画基本完成,这时候resize才准确。这个300ms不是随便定的,是我在多个浏览器上实测下来的经验值,Chrome大概200ms,Firefox大概250ms,留300ms比较保险。

3. 全屏后图表自适应的核心机制

全屏功能本身不难,难的是全屏之后图表要跟着自适应。ECharts、Chart.js这些图表库默认不会自动监听容器尺寸变化,需要你手动调用resize方法。

3.1 ECharts的resize机制拆解

ECharts的resize方法有两种调用方式:

// 方式一:不传参数,图表自动获取容器尺寸 chart.resize(); // 方式二:传入具体宽高 chart.resize({ width: 800, height: 600 });

大多数场景用方式一就行。但方式一有个前提:图表的容器必须有明确的宽高,而且宽高是通过CSS计算出来的。如果容器宽高是0,resize会失效。

全屏场景下,容器宽高会从原来的尺寸变成屏幕尺寸,这个变化ECharts是感知不到的,必须你手动调用resize。问题是什么时候调用?如果只监听fullscreenchange事件,在事件回调里立即调用resize,可能会拿到错误的尺寸。所以我在上面代码里用了setTimeout延迟300ms。

但延迟300ms也有问题:如果用户快速切换全屏,可能会触发多次resize,造成性能浪费。更好的做法是用防抖:

// 防抖处理resize function debounce(fn, delay) { let timer = null; return function(...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); }, delay); }; } const handleResize = debounce(() => { // 遍历所有图表实例,逐个resize chartInstances.forEach(chart => { if (chart && !chart.isDisposed()) { chart.resize(); } }); }, 300); window.addEventListener('resize', handleResize); FullscreenHelper.onFullscreenChange(handleResize);

这里有个关键点:chart.isDisposed()判断。如果图表已经被销毁了,再调用resize会报错。在Vue或React组件里,组件销毁时图表也会销毁,但resize事件可能还在触发,所以必须加这个判断。

3.2 多图表实例的统一管理

大屏项目通常有多个图表,如果每个图表都单独监听resize,代码会很乱。我建议用一个统一的图表管理器:

// 图表管理器 class ChartManager { constructor() { this.charts = new Map(); this.resizeHandler = debounce(this.resizeAll.bind(this), 300); this.initListeners(); } // 注册图表 register(id, chartInstance) { this.charts.set(id, chartInstance); } // 注销图表 unregister(id) { const chart = this.charts.get(id); if (chart && !chart.isDisposed()) { chart.dispose(); } this.charts.delete(id); } // 全部resize resizeAll() { this.charts.forEach((chart, id) => { if (chart && !chart.isDisposed()) { try { chart.resize(); } catch (err) { console.warn(`图表${id} resize失败:`, err.message); } } }); } // 初始化监听 initListeners() { window.addEventListener('resize', this.resizeHandler); FullscreenHelper.onFullscreenChange(this.resizeHandler); } // 销毁 destroy() { window.removeEventListener('resize', this.resizeHandler); this.charts.forEach(chart => { if (chart && !chart.isDisposed()) { chart.dispose(); } }); this.charts.clear(); } } // 全局单例 export const chartManager = new ChartManager();

用管理器的方式,每个图表组件只需要在mounted时register,在unmounted时unregister,resize逻辑完全解耦。这样即使有几十个图表,代码也不会乱。

3.3 全屏切换时的图表动画衔接

全屏切换时,图表如果直接resize,会有一种"跳变"的感觉,视觉上不够流畅。我试过几种优化方案:

方案一是在resize时加过渡动画。ECharts的resize不支持动画参数,但你可以用CSS给容器加transition:

.chart-container { transition: width 0.3s ease, height 0.3s ease; }

但这种方式有个问题:ECharts的canvas尺寸是JS控制的,CSS transition只对容器生效,canvas本身不会平滑过渡,所以效果有限。

方案二是用ECharts的setOption重新渲染。全屏后重新setOption,ECharts会有一个默认的过渡动画。但这种方式性能开销大,图表多了会卡。

方案三是我最终采用的:全屏切换时先隐藏图表,等resize完成后再显示。这样用户看到的是"隐藏-显示"的过程,而不是"跳变"。

// 全屏切换时的图表处理 async function handleFullscreenToggle() { // 1. 隐藏所有图表容器 document.querySelectorAll('.chart-container').forEach(el => { el.style.opacity = '0'; }); // 2. 切换全屏 if (isFullscreen.value) { FullscreenHelper.exitFullscreen(); } else { FullscreenHelper.requestFullscreen(targetRef.value); } // 3. 等待全屏动画完成 await new Promise(resolve => setTimeout(resolve, 350)); // 4. resize所有图表 chartManager.resizeAll(); // 5. 显示图表 document.querySelectorAll('.chart-container').forEach(el => { el.style.opacity = '1'; }); }

这个方案实测下来视觉最流畅,用户几乎感觉不到图表在切换过程中的变化。

4. 大屏全屏功能的完整交互设计

全屏不是孤立的按钮,它和整个大屏的交互体系是联动的。这部分我讲讲实际项目中的交互设计经验。

4.1 全屏按钮的状态同步

全屏按钮需要根据当前状态切换图标和文案。但状态同步有个坑:用户可能通过多种方式进入/退出全屏,比如点击按钮、按ESC、按F11。你必须保证所有方式都能正确同步状态。

// 全屏按钮组件 const FullscreenButton = { template: ` <button class="fullscreen-btn" @click="toggle" :title="isFullscreen ? '退出全屏' : '进入全屏'"> <i :class="isFullscreen ? 'icon-exit-fullscreen' : 'icon-fullscreen'"></i> </button> `, setup() { const targetRef = ref(null); const { isFullscreen, toggleFullscreen } = useFullscreen(targetRef); return { isFullscreen, toggle: toggleFullscreen }; } };

这里的关键是useFullscreen里监听了fullscreenchange事件,所以不管用户怎么切换全屏,isFullscreen都会正确更新。如果你只在按钮点击时改状态,用户按ESC退出后按钮状态就不对了。

4.2 ESC键退出的拦截与处理

默认情况下,用户按ESC会退出全屏。但有些大屏项目希望拦截ESC,比如在ESC退出前弹个确认框,或者ESC只退出某个弹窗而不退出全屏。

拦截ESC有个前提:你必须先进入全屏,才能拦截。因为ESC的keydown事件在非全屏状态下是浏览器级别的,页面拿不到。

// 拦截ESC退出全屏 document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && isFullscreen.value) { // 如果当前有弹窗打开,只关闭弹窗 if (hasOpenModal()) { closeTopModal(); e.preventDefault(); return; } // 否则正常退出全屏,不做拦截 } });

注意:e.preventDefault()在全屏状态下对ESC的拦截效果因浏览器而异。Chrome下可以拦截,Firefox下拦截不了。所以如果你的项目需要严格拦截ESC,建议用全屏API的exitFullscreen配合自定义快捷键,而不是依赖ESC。

4.3 全屏状态下的鼠标隐藏

大屏演示时,鼠标指针如果一直显示,会影响视觉效果。可以在全屏状态下自动隐藏鼠标,用户移动鼠标时再显示。

// 全屏状态下自动隐藏鼠标 let mouseTimer = null; function setupMouseHide() { document.addEventListener('mousemove', () => { if (!isFullscreen.value) return; document.body.style.cursor = 'default'; if (mouseTimer) clearTimeout(mouseTimer); mouseTimer = setTimeout(() => { document.body.style.cursor = 'none'; }, 3000); }); }

这个功能看起来小,但实际演示时体验提升很明显。3秒是我测试下来比较合适的值,太短了用户会觉得鼠标老是消失,太长了又起不到隐藏效果。

4.4 全屏与页面缩放的冲突处理

大屏项目通常会用rem或scale做整体缩放适配。全屏后,如果缩放逻辑没处理好,会出现图表模糊或者布局错位。

我的做法是:全屏时重新计算缩放比例。假设设计稿是1920x1080,全屏后屏幕是2560x1440,缩放比例应该是min(2560/1920, 1440/1080) = 1.333。

// 全屏时重新计算缩放 function recalcScale() { const designWidth = 1920; const designHeight = 1080; const screenWidth = window.innerWidth; const screenHeight = window.innerHeight; const scaleX = screenWidth / designWidth; const scaleY = screenHeight / designHeight; const scale = Math.min(scaleX, scaleY); const container = document.querySelector('.dashboard-container'); container.style.transform = `scale(${scale})`; container.style.transformOrigin = 'left top'; // 居中处理 const offsetX = (screenWidth - designWidth * scale) / 2; const offsetY = (screenHeight - designHeight * scale) / 2; container.style.left = `${offsetX}px`; container.style.top = `${offsetY}px`; }

这里用Math.min而不是Math.max,是为了保证内容完整显示,不会被裁切。如果屏幕比例和设计稿比例不一致,会出现黑边,这是正常的,总比内容被裁掉好。

5. 踩坑实录:那些让我加班到凌晨的全屏问题

这部分我讲讲实际项目中遇到的具体问题,都是真实踩过的坑,希望能帮你少走弯路。

5.1 iframe嵌套下的全屏失效

大屏项目有时候会嵌入iframe,比如把某个子页面嵌到主页面里。这时候在iframe内部调用requestFullscreen会失败,报错"Fullscreen request denied"。

原因是iframe默认没有全屏权限,需要在iframe标签上加allowfullscreen属性:

<iframe src="child.html" allowfullscreen></iframe>

如果是跨域的iframe,还需要在响应头里加Permissions-Policy: fullscreen=(self "https://父页面域名")。这个配置很容易漏,漏了之后全屏就是静默失败,控制台可能都不报错。

5.2 全屏后ECharts图表模糊

这个问题困扰了我很久。全屏后图表变模糊,原因是ECharts的canvas分辨率没有跟着设备像素比(devicePixelRatio)更新。

ECharts默认会用window.devicePixelRatio作为canvas的像素比。但在全屏切换时,如果devicePixelRatio变了(比如从普通屏幕切到Retina屏),ECharts不会自动更新。

解决方案是在resize时手动传入devicePixelRatio:

chart.resize({ width: 'auto', height: 'auto', // 强制使用当前设备像素比 devicePixelRatio: window.devicePixelRatio });

但注意,ECharts的resize方法其实不支持devicePixelRatio参数。正确的做法是在初始化时设置,或者在resize后重新setOption:

// 方案:销毁重建 function rebuildChart(chartInstance, container, option) { chartInstance.dispose(); const newChart = echarts.init(container, null, { devicePixelRatio: window.devicePixelRatio }); newChart.setOption(option); return newChart; }

销毁重建的性能开销大,但能彻底解决模糊问题。如果图表不多,这个方案可以接受。如果图表很多,建议只在检测到devicePixelRatio变化时才重建。

5.3 全屏切换时的白屏闪烁

全屏切换时,页面会有一个短暂的白屏。原因是浏览器在全屏动画过程中会重新绘制页面,如果页面背景是白色的,就会闪白。

解决方案很简单:把body和html的背景色设成深色,和大屏主题一致。

html, body { background-color: #0a0e27; margin: 0; padding: 0; overflow: hidden; }

这个细节很小,但不处理的话,演示时白屏闪烁很影响观感。

5.4 移动端全屏的特殊处理

移动端浏览器的全屏API和桌面端不一样。iOS Safari不支持Fullscreen API,Android Chrome支持但行为有差异。

iOS上的替代方案是用webkitEnterFullscreen,但只对video元素有效。对于普通div,iOS没有真正的全屏方案,只能用CSS伪全屏模拟。

// 移动端全屏兼容 function mobileFullscreen(element) { // iOS不支持标准全屏API if (/iPhone|iPad|iPod/.test(navigator.userAgent)) { // 用CSS模拟 element.style.position = 'fixed'; element.style.top = '0'; element.style.left = '0'; element.style.width = '100vw'; element.style.height = '100vh'; element.style.zIndex = '9999'; // 隐藏地址栏 window.scrollTo(0, 1); return; } // Android用标准API FullscreenHelper.requestFullscreen(element); }

移动端大屏项目相对少,但如果你的项目需要兼容移动端,这块必须处理。

5.5 全屏状态下的键盘快捷键冲突

大屏项目通常有一些快捷键,比如数字键切换页面、方向键翻页。全屏状态下,这些快捷键可能和浏览器快捷键冲突。

比如你按F5刷新,全屏状态下F5依然有效,会刷新页面并退出全屏。如果你不希望用户刷新,可以拦截:

document.addEventListener('keydown', (e) => { // 拦截F5刷新 if (e.key === 'F5' || (e.ctrlKey && e.key === 'r')) { e.preventDefault(); return false; } // 拦截F11 if (e.key === 'F11') { e.preventDefault(); // 用自定义全屏替代 toggleFullscreen(); return false; } });

但注意,拦截浏览器快捷键是有风险的,用户可能会觉得"我的浏览器怎么不受控制了"。建议只在演示模式下拦截,正常浏览时不要拦截。

6. 全屏功能的性能优化与异常兜底

全屏功能虽然不复杂,但在大屏项目里,性能问题和异常情况必须考虑周全。

6.1 resize的性能优化

大屏项目图表多,每次resize都遍历所有图表,如果图表有几十个,会有明显的卡顿。优化思路有三个:

第一个是防抖,这个前面已经讲了,300ms的防抖能过滤掉大部分无效resize。

第二个是懒resize,只resize当前可见的图表。如果大屏有多个页面,只有当前页的图表需要resize,其他页的可以等切换过去再resize。

// 懒resize:只处理可见图表 resizeVisible() { this.charts.forEach((chart, id) => { const container = chart.getDom(); // 判断容器是否可见 if (container.offsetParent !== null && !chart.isDisposed()) { chart.resize(); } }); }

第三个是用requestAnimationFrame替代setTimeout,让resize在下一帧渲染前执行,避免布局抖动。

// 用requestAnimationFrame优化 let rafId = null; function scheduleResize() { if (rafId) cancelAnimationFrame(rafId); rafId = requestAnimationFrame(() => { chartManager.resizeAll(); }); }

6.2 全屏API失败的兜底方案

Fullscreen API不是100%可靠的,可能因为各种原因失败。你需要有兜底方案:

// 全屏失败兜底 function safeFullscreen(element) { const success = FullscreenHelper.requestFullscreen(element); if (!success) { // API不支持,用CSS伪全屏兜底 fallbackFullscreen(element); return; } // 监听全屏是否真的成功了 setTimeout(() => { if (!FullscreenHelper.getFullscreenElement()) { // 3秒后还没进入全屏,说明失败了 console.warn('全屏未生效,启用兜底方案'); fallbackFullscreen(element); } }, 3000); } function fallbackFullscreen(element) { element.classList.add('pseudo-fullscreen'); // 同时隐藏浏览器UI(能隐藏多少算多少) window.scrollTo(0, 1); }

兜底方案虽然不如原生全屏完美,但至少能保证功能可用,不会让用户点了按钮没反应。

6.3 内存泄漏的排查与预防

全屏功能涉及事件监听,如果组件销毁时没清理干净,会造成内存泄漏。常见的泄漏点有:

  • fullscreenchange事件监听没移除
  • resize事件监听没移除
  • 图表实例没dispose
  • setTimeout没clear

我在项目里加了一个检查机制,在组件销毁时打印未清理的监听器数量:

// 开发环境下的泄漏检查 if (process.env.NODE_ENV === 'development') { const originalAdd = document.addEventListener; const originalRemove = document.removeEventListener; let listenerCount = 0; document.addEventListener = function(...args) { listenerCount++; return originalAdd.apply(this, args); }; document.removeEventListener = function(...args) { listenerCount--; return originalRemove.apply(this, args); }; window.__checkLeak = () => { console.log(`当前监听器数量: ${listenerCount}`); if (listenerCount > 10) { console.warn('可能存在内存泄漏,请检查事件监听是否清理'); } }; }

这个检查机制在开发阶段很有用,能帮你提前发现泄漏问题。

6.4 全屏状态持久化

有些项目希望用户刷新页面后还能保持全屏状态。但浏览器的安全策略不允许页面加载时自动进入全屏,必须由用户交互触发。

折中方案是用localStorage记录全屏状态,页面加载后显示一个"点击恢复全屏"的提示:

// 记录全屏状态 FullscreenHelper.onFullscreenChange(() => { const isFull = !!FullscreenHelper.getFullscreenElement(); localStorage.setItem('dashboard_fullscreen', isFull ? '1' : '0'); }); // 页面加载时检查 window.addEventListener('load', () => { if (localStorage.getItem('dashboard_fullscreen') === '1') { // 显示恢复全屏的提示 showRestoreFullscreenTip(); } });

这个方案虽然不是真正的自动恢复,但用户体验上比完全丢失状态好。

7. 写在最后的一些实战心得

全屏功能做了这么多次,我最大的体会是:不要小看任何一个"简单"的功能。Fullscreen API看起来就几个方法,但真正要做好,需要考虑兼容性、状态同步、图表自适应、性能优化、异常兜底等一堆细节。

如果你正在做大屏项目,我的建议是:全屏功能不要等到最后再做,最好在项目初期就把框架搭好。因为全屏涉及到布局、图表、交互等多个模块,后期再加会很痛苦。

另外,测试的时候一定要在真实的大屏设备上测,不要只在开发机的浏览器里测。大屏的分辨率、设备像素比、浏览器版本都可能和开发机不一样,很多问题只有在大屏上才会暴露。

最后分享一个我常用的调试技巧:在全屏状态下打开控制台,用document.fullscreenElement查看当前全屏元素,用window.innerWidth和window.innerHeight查看实际尺寸,用window.devicePixelRatio查看像素比。这三个值能帮你快速定位大部分全屏相关的问题。

返回列表