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 次以上显示构建版本信息(供测试人员使用)