uni-app启动页无法用Vue页面直接实现,因原生启动图在JS环境加载前已显示;需通过pages/splash/splash.vue模拟开屏页,配合setTimeout倒计时、uni.hideLoading等统一清理遮罩,并预加载目标页优化体验。

uni-app 启动页不能直接用 Vue 页面实现
uni-app 的启动页(Splash Page)在 iOS 和 Android 原生层加载,App.vue 或首页 pages/index/index.vue 渲染前就已显示。这意味着你无法在 Vue 里“控制”原生启动图的显隐或倒计时——它压根还没进 JS 环境。
真正能自定义的,是「原生启动页之后、Vue 实例挂载之前」那一段空白过渡期。这时候需要靠 uni.showLoading + 手动控制跳转来模拟「开屏页」效果。
- 原生启动图(
splash.png)仅支持静态图,iOS 要求尺寸固定,Android 需按 density 放多套资源 - 所谓“倒计时跳过”,实际是原生启动图消失后,立刻展示一个全屏 Vue 页面,并在该页面内做倒计时和跳过逻辑
- 如果直接在
App.vue里写倒计时,会看到明显白屏闪动——因为原生启动图关闭和 Vue 渲染之间有延迟
用 pages/splash/splash.vue 模拟开屏页
新建一个页面作为“伪启动页”,设为应用首个加载页面(在 pages.json 中置顶),并禁用导航栏和下拉刷新:
"pages": [{
"path": "pages/splash/splash",
"style": {
"navigationStyle": "custom",
"disableScroll": true,
"usingComponents": false
}
}]
这个页面要满足三个条件:全屏、无交互干扰、倒计时结束自动跳转。关键点在于避免用户误点穿透到下层页面(比如底部 tabbar 还没隐藏干净)。
- 用
position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;确保覆盖全屏,别依赖uni.getSystemInfo动态算高度 - 倒计时用
setTimeout而非setInterval,避免多次跳转或内存泄漏(页面onUnload时不用手动清除) - 跳过按钮绑定
@click="jump",但必须加catchtouchmove阻止默认滚动行为,否则 iOS 上快速滑动可能触发页面滚动露出底色
uni.navigateTo 跳转前要关掉 loading 和 mask
很多开发者在倒计时期间调用 uni.showLoading 显示“加载中”,结果跳转后 loading 还挂在那儿——因为 uni.hideLoading 没被调用,或者调用时机不对。
更隐蔽的问题是:如果你用了 uni.showModal 或 uni.showToast,它们自带遮罩层(mask),而 uni.navigateTo 不会自动关闭这些遮罩。用户会卡在半透明黑屏里,以为卡死了。
- 所有倒计时结束逻辑统一走一个函数,开头先执行
uni.hideLoading()、uni.hideToast()、uni.hideModal() - 跳转前加
uni.preloadPage预加载目标页(如首页),减少白屏时间,尤其对分包项目有效 - 不要在
onLoad里才开始预加载,应该在 splash 页面onShow就启动,倒计时只是个视觉缓冲
Android 上倒计时不准?检查 plus.runtime.getProperty
部分安卓机型(尤其 MIUI、EMUI)会限制前台服务或定时器精度,导致 setTimeout 延迟高达 500ms+,3 秒倒计时可能变成 3.8 秒才跳转。这不是代码 bug,是系统策略。
想绕过?可以用 plus.runtime.getProperty('buildDate') 获取原生层启动时间戳,再用 Date.now() 对比计算剩余时间,比纯 JS 定时器更稳。
- 只在 App 端生效,H5 不支持
plus对象,需加判断:if (uni.getSystemInfoSync().platform === 'app') - 首次获取
buildDate可能返回空,建议 fallback 到Date.now()并打日志排查 - 别依赖
plus.navigator.closeSplashscreen—— 它只能关闭原生启动图,且调用后无法再恢复,和你的 Vue 开屏页无关
真正难搞的是冷启动时的首帧渲染延迟,不同设备差异大。与其死磕倒计时毫秒级准确,不如把「跳过」按钮做得足够醒目,让用户有掌控感。










