From edea8c32de596f51b61243f3a5395c4a0f15aa90 Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Mon, 13 Jul 2026 10:36:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(splash-screen):=20=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E5=B1=8F=E7=AD=89=E5=BE=85=E9=A6=96=E9=A1=B5=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E5=B0=B1=E7=BB=AA=E5=90=8E=E5=86=8D=E6=B6=88=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题描述: 首次启动时,启动屏已关闭但首页内容还是空白的,用户体验差。 解决方案: 1. 在 splash-state.js 中新增页面就绪等待机制 (_pageReady 标志、notifyPageReady 方法) 2. 修改软隐藏逻辑,必须同时满足组件已 mount 和页面已就绪才关闭启动屏 3. 在首页 onDiyGroupLoaded 回调中通知页面就绪 兜底保护: - 组件 1s 未 mount → 强制关闭 - 页面 2s 未就绪 → 强制关闭 - 总超时 8s → 强制关闭 --- common/js/splash-state.js | 60 ++++++++++++++++++++++++++++++---- pages/index/public/js/index.js | 4 +++ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/common/js/splash-state.js b/common/js/splash-state.js index 5f66b6f..ebc6360 100644 --- a/common/js/splash-state.js +++ b/common/js/splash-state.js @@ -35,6 +35,7 @@ function useNativeLoading() { const DEFAULT_TIMEOUT = 8000; // 总兜底超时 const MOUNT_GRACE_MS = 1000; // 软隐藏后等组件 mount 的宽限时间 +const PAGE_READY_GRACE_MS = 2000; // 软隐藏后等页面就绪的宽限时间 // 启动期阶段定义 (id → { percent, label }) // percent: 阶段完成的百分比 (0-100) @@ -56,9 +57,12 @@ class SplashState { this._listeners = []; this._shownAt = 0; // 软隐藏相关 - this._pendingHide = null; // 软隐藏请求的 opts, 等待组件 mount - this._hasMounted = false; // 是否有 splash 组件 mount 过 - this._mountGraceId = null; // 软隐藏兜底定时器 + this._pendingHide = null; // 软隐藏请求的 opts, 等待组件 mount + this._hasMounted = false; // 是否有 splash 组件 mount 过 + this._mountGraceId = null; // 软隐藏兜底定时器 (等 mount) + // 页面就绪等待 + this._pageReady = false; // 页面内容是否已就绪 (由首页通知) + this._pageReadyGraceId = null; // 页面就绪兜底定时器 // 进度上报 this._stage = 'boot'; this._percent = 0; @@ -77,6 +81,7 @@ class SplashState { this._shownAt = Date.now(); this._pendingHide = null; this._hasMounted = false; + this._pageReady = false; this._stage = 'boot'; // 初始化时直接显示 'boot' 阶段的 5%, 而不是 0% // 避免首帧出现"进度条 0%"的视觉突兀 @@ -91,6 +96,10 @@ class SplashState { clearTimeout(this._mountGraceId); this._mountGraceId = null; } + if (this._pageReadyGraceId) { + clearTimeout(this._pageReadyGraceId); + this._pageReadyGraceId = null; + } this._emit('splash:show'); // H5 降级: 走系统 loading (Vue 还没挂载,组件层无法渲染) @@ -138,15 +147,16 @@ class SplashState { } /** - * 软隐藏: 标记应该 hide, 等组件 mount + * 软隐藏: 标记应该 hide, 等组件 mount + 页面就绪 * 如果组件 1s 内没 mount, 兜底自动 hide + * 如果页面 2s 内没就绪, 兜底自动 hide */ _softHide(opts) { if (!this._visible) return; // 已经隐藏了 this._pendingHide = opts; - // 如果组件已经 mount, 立即隐藏 - if (this._hasMounted) { + // 如果组件已经 mount 且页面已就绪, 立即隐藏 + if (this._hasMounted && this._pageReady) { this._flushPendingHide(); return; } @@ -162,6 +172,7 @@ class SplashState { /** * 真正触发软隐藏 + * 如果页面还未就绪, 等待页面就绪后再 hide */ _flushPendingHide() { const opts = this._pendingHide; @@ -170,6 +181,20 @@ class SplashState { clearTimeout(this._mountGraceId); this._mountGraceId = null; } + + // 如果页面还未就绪, 等待页面就绪 + if (!this._pageReady) { + // 兜底: 2s 内没就绪, 强制隐藏 + if (this._pageReadyGraceId) clearTimeout(this._pageReadyGraceId); + this._pageReadyGraceId = setTimeout(() => { + if (this._visible) { + console.warn('[splash-state] auto-hide after page-ready timeout'); + this._doHide(opts || { reason: 'page-ready-timeout' }); + } + }, PAGE_READY_GRACE_MS); + return; + } + this._doHide(opts || { reason: 'mount-completed' }); } @@ -186,6 +211,10 @@ class SplashState { clearTimeout(this._mountGraceId); this._mountGraceId = null; } + if (this._pageReadyGraceId) { + clearTimeout(this._pageReadyGraceId); + this._pageReadyGraceId = null; + } this._pendingHide = null; this._visible = false; // H5 降级对应的关闭 @@ -217,6 +246,25 @@ class SplashState { } } + /** + * 页面内容就绪后通知 state 模块 + * - 标记 _pageReady + * - 如果有 _pendingHide, 触发真关 + * 调用时机: 首页 diy-group 渲染完成后调用 + */ + notifyPageReady() { + if (this._pageReady) return; + this._pageReady = true; + if (this._pageReadyGraceId) { + clearTimeout(this._pageReadyGraceId); + this._pageReadyGraceId = null; + } + if (this._pendingHide) { + // 给页面一帧时间完成渲染, 再隐藏 + setTimeout(() => this._flushPendingHide(), 50); + } + } + /** * 组件 unmount 时通知 (用于 _hasMounted 状态管理) * 目前保留 _hasMounted=true, 因为一般只有 tab 页有 splash 组件, 不会动态增减 diff --git a/pages/index/public/js/index.js b/pages/index/public/js/index.js index 61041ba..3fef1eb 100644 --- a/pages/index/public/js/index.js +++ b/pages/index/public/js/index.js @@ -1,3 +1,5 @@ +import splashState from '@/common/js/splash-state.js'; + export default { data() { return { @@ -124,8 +126,10 @@ export default { return false; }, // diy-group 渲染完毕回调, 用于触发版本水印等延后显示元素 + // 同时通知 splash-state 页面就绪, 启动屏可以关闭 onDiyGroupLoaded() { this.diyGroupReady = true; + try { splashState.notifyPageReady(); } catch (e) {} }, /** * 版本连击 3 次以上显示构建版本信息(供测试人员使用)