feat(splash-screen): add configurable splash screen display options
add splashConfig in config-external.js to control progress/label/percent display, add runtime config api in splash-state.js, refactor splash-screen.vue to support inline layout and prop override
This commit is contained in:
@@ -158,6 +158,21 @@ export const privacyConfig = {
|
||||
// },
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// 启动屏配置 (与 privacyConfig 同构, 由 splash-state.js 消费)
|
||||
// showProgress 是否显示进度条本身 + 数字 (label 单独可独立关闭)
|
||||
// showLabel 是否显示阶段文案 (Loading language... 等)
|
||||
// showPercent 是否显示百分比数字
|
||||
// showProgress=true + showLabel=false + showPercent=true → 只显示进度条+百分比
|
||||
// showProgress=false → 整个进度条区域隐藏
|
||||
// 业务侧可改 splashConfig.* 或在 splash 组件 <splash-screen :show-label="false" /> 覆盖
|
||||
// ============================================================
|
||||
export const splashConfig = {
|
||||
showProgress: true,
|
||||
showLabel: false, // 默认 false: 用户想要"只显示百分比"
|
||||
showPercent: true,
|
||||
}
|
||||
|
||||
// 配置外置管理类
|
||||
class ConfigExternal {
|
||||
constructor() {
|
||||
|
||||
@@ -10,8 +10,12 @@
|
||||
// 4. 兜底超时: 默认 8s 未关闭则强制 hide,防止卡死
|
||||
// 5. 平台隔离: APP-PLUS 有原生 splash,这里直接返回 false
|
||||
// 6. 跨平台兼容: 同步状态可被 Vue 组件直接 watch
|
||||
// 7. 可配置: splashConfig 支持 showProgress/showLabel/showPercent 单独控制
|
||||
// 业务侧可在 config-external.js 改 splashConfig, 或 <splash-screen :show-label="false" /> 覆盖
|
||||
// ============================================================
|
||||
|
||||
import { splashConfig as _defaultSplashConfig } from './config-external.js'
|
||||
|
||||
// APP-PLUS 直接返回 false (有原生启动屏)
|
||||
function needSplash() {
|
||||
// #ifdef APP-PLUS
|
||||
@@ -67,6 +71,8 @@ class SplashState {
|
||||
// 避免多通道并发时, splash 组件 re-render 风暴
|
||||
this._pendingProgress = null; // 待 emit 的最新进度
|
||||
this._flushTimer = null; // 节流定时器
|
||||
// 启动屏显示配置: 初始读 config-external.js 的 splashConfig, 可运行时改
|
||||
this._splashConfig = Object.assign({}, _defaultSplashConfig)
|
||||
}
|
||||
|
||||
show(opts = {}) {
|
||||
@@ -343,6 +349,33 @@ getStageDef(stageId) {
|
||||
return STAGES[stageId]
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取启动屏显示配置
|
||||
* splash 组件读这个决定 label/percent 是否显示
|
||||
* 缺字段时回退到默认 (splashConfig=true)
|
||||
* @returns {{showProgress: boolean, showLabel: boolean, showPercent: boolean}}
|
||||
*/
|
||||
getSplashConfig() {
|
||||
const c = this._splashConfig || {}
|
||||
return {
|
||||
showProgress: c.showProgress !== false,
|
||||
showLabel: !!c.showLabel,
|
||||
showPercent: c.showPercent !== false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 运行时合并更新 splash 配置
|
||||
* 全局 splashConfig 在 boot 前注入; 业务运行时改某些字段可用本方法
|
||||
* 不会触发组件 re-render (splash 组件用 props 优先)
|
||||
* @param {Object} partial
|
||||
*/
|
||||
setSplashConfig(partial) {
|
||||
if (!partial || typeof partial !== 'object') return
|
||||
this._splashConfig = Object.assign({}, this._splashConfig, partial)
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即刷新挂起的进度更新
|
||||
* - reportProgress 默认 16ms throttle (1 帧), 避免连续触发 splash 组件多次 re-render
|
||||
|
||||
@@ -23,14 +23,28 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 启动期进度条 (透明悬浮, 不干扰极光视觉) -->
|
||||
<view class="splash-screen__progress" v-if="showProgress">
|
||||
<view class="splash-screen__progress-bar">
|
||||
<view class="splash-screen__progress-fill" :style="{ width: percent + '%' }"></view>
|
||||
<!-- 启动期进度条 (透明悬浮, 不干扰极光视觉)
|
||||
布局: showLabel 和 showPercent 可独立控制
|
||||
- showLabel=true, showPercent=true: label 在上, percent 在下 (原始布局)
|
||||
- showLabel=false, showPercent=true: 只有进度条 + percent 在右侧
|
||||
-->
|
||||
<view v-if="displayConfig.showProgress">
|
||||
<!-- 1) inline 模式: showLabel=false, showPercent=true -->
|
||||
<view v-if="inlineMode" class="splash-screen__progress-row">
|
||||
<view class="splash-screen__progress-bar splash-screen__progress-bar--inline">
|
||||
<view class="splash-screen__progress-fill" :style="{ width: percent + '%' }"></view>
|
||||
</view>
|
||||
<text class="splash-screen__progress-percent splash-screen__progress-percent--inline">{{ percent }}%</text>
|
||||
</view>
|
||||
<view class="splash-screen__progress-text">
|
||||
<text class="splash-screen__progress-stage">{{ stageLabel }}</text>
|
||||
<text class="splash-screen__progress-percent">{{ percent }}%</text>
|
||||
<!-- 2) 普通模式: 进度条 + label/percent 文本 -->
|
||||
<view v-else class="splash-screen__progress">
|
||||
<view v-if="displayConfig.showPercent" class="splash-screen__progress-bar splash-screen__progress-bar--full">
|
||||
<view class="splash-screen__progress-fill" :style="{ width: percent + '%' }"></view>
|
||||
</view>
|
||||
<view v-if="displayConfig.showLabel || displayConfig.showPercent" class="splash-screen__progress-text">
|
||||
<text v-if="displayConfig.showLabel" class="splash-screen__progress-stage">{{ stageLabel }}</text>
|
||||
<text v-if="displayConfig.showPercent" class="splash-screen__progress-percent">{{ percent }}%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -42,6 +56,23 @@
|
||||
|
||||
export default {
|
||||
name: 'splash-screen',
|
||||
// props 优先级: 页面级 <splash-screen :hide-label /> > splashState.getSplashConfig()
|
||||
// 任何 prop 为 undefined 时回退全局, 给业务侧最大灵活性
|
||||
// 注意: prop 命名前缀 'display' 避免与未来 splash-state 内部字段同名引起 Vue prop-mutation 误判
|
||||
props: {
|
||||
hideProgress: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
hideLabel: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
hidePercent: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 默认 visible=true: 让 splash 组件一渲染就可见, 减少"白屏闪烁"
|
||||
@@ -51,16 +82,32 @@
|
||||
leaving: false,
|
||||
percent: 0,
|
||||
stage: 'boot',
|
||||
showProgress: false,
|
||||
// 内部 showProgress 标志 (保留兼容, 由 created() 维护)
|
||||
// 实际模板用 displayConfig.showProgress 决定, 这个内部标志走原逻辑
|
||||
_showProgressLegacy: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 直接从 splashState.STAGES 读取文案, 避免重复维护 STAGE_LABEL
|
||||
// (splash-state.js 暴露 getStageDef() 避免外部直接读 STAGES)
|
||||
stageLabel() {
|
||||
const def = splashState.getStageDef(this.stage)
|
||||
return def ? def.label : this.stage
|
||||
},
|
||||
// 显示配置: props 优先 (hide 语义, false=show), 否则回退全局 splashConfig
|
||||
// 注意: splashConfig 的 show* 是肯定语义 (true=show), 我们这里 hide* 取反
|
||||
displayConfig() {
|
||||
const cfg = splashState.getSplashConfig()
|
||||
return {
|
||||
showProgress: this.hideProgress !== undefined ? !this.hideProgress : cfg.showProgress,
|
||||
showLabel: this.hideLabel !== undefined ? !this.hideLabel : cfg.showLabel,
|
||||
showPercent: this.hidePercent !== undefined ? !this.hidePercent : cfg.showPercent,
|
||||
}
|
||||
},
|
||||
// inline 布局: 只显示百分比 + 进度条 (label 隐藏)
|
||||
// 此时进度条和百分比在同一水平线 (flex)
|
||||
inlineMode() {
|
||||
return this.displayConfig.showPercent && !this.displayConfig.showLabel
|
||||
},
|
||||
},
|
||||
// created (而非 mounted): 提前同步 splashState 状态, 减少"白屏一帧"
|
||||
created() {
|
||||
@@ -68,7 +115,10 @@
|
||||
const init = splashState.getProgress()
|
||||
this.percent = init.percent
|
||||
this.stage = init.stage
|
||||
this.showProgress = init.percent > 0
|
||||
// _showProgressLegacy 控制 progress-fade-in CSS 动画触发
|
||||
// (true → 触发 CSS 关键帧; false → 隐藏整个进度区)
|
||||
// 模板用 displayConfig.showProgress 综合 props + splashConfig 决定
|
||||
this._showProgressLegacy = init.percent > 0
|
||||
} catch (e) {}
|
||||
// 同步 splashState 状态: 防止组件挂载在 splash 已 hide 之后误显示
|
||||
if (!splashState.isShow()) {
|
||||
@@ -76,34 +126,34 @@
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
splashState.notifyMounted();
|
||||
splashState.on('splash:show', () => {
|
||||
this.visible = true;
|
||||
this.leaving = false;
|
||||
// 注意: 不要在这里再读 getProgress(). percent 不允许后退
|
||||
// 已通过 created() 同步; emit 进来多是无变化
|
||||
const init = splashState.getProgress()
|
||||
if (init.percent > this.percent) this.percent = init.percent
|
||||
if (init.stage !== this.stage) this.stage = init.stage
|
||||
this.showProgress = true
|
||||
});
|
||||
splashState.on('splash:hide', (info) => {
|
||||
// 进度条补完到 100% (视觉上"完成"), 立即 leave
|
||||
if (this.percent < 100) {
|
||||
this.percent = 100;
|
||||
this.stage = 'done';
|
||||
}
|
||||
// mode='fast' (隐私弹窗即将出现) → 80ms 短动画让 modal 更快接管视觉
|
||||
const fast = info && info.mode === 'fast'
|
||||
this._leave(fast)
|
||||
});
|
||||
splashState.onProgress((info) => {
|
||||
// 去重: percent/stage 没变化就不 setState, 避免空 re-render
|
||||
if (info.percent !== this.percent) this.percent = info.percent
|
||||
if (info.stage !== this.stage) this.stage = info.stage
|
||||
this.showProgress = true;
|
||||
});
|
||||
},
|
||||
splashState.notifyMounted();
|
||||
splashState.on('splash:show', () => {
|
||||
this.visible = true;
|
||||
this.leaving = false;
|
||||
// 注意: 不要在这里再读 getProgress(). percent 不允许后退
|
||||
// 已通过 created() 同步; emit 进来多是无变化
|
||||
const init = splashState.getProgress()
|
||||
if (init.percent > this.percent) this.percent = init.percent
|
||||
if (init.stage !== this.stage) this.stage = init.stage
|
||||
this._showProgressLegacy = true
|
||||
});
|
||||
splashState.on('splash:hide', (info) => {
|
||||
// 进度条补完到 100% (视觉上"完成"), 立即 leave
|
||||
if (this.percent < 100) {
|
||||
this.percent = 100;
|
||||
this.stage = 'done';
|
||||
}
|
||||
// mode='fast' (隐私弹窗即将出现) → 80ms 短动画让 modal 更快接管视觉
|
||||
const fast = info && info.mode === 'fast'
|
||||
this._leave(fast)
|
||||
});
|
||||
splashState.onProgress((info) => {
|
||||
// 去重: percent/stage 没变化就不 setState, 避免空 re-render
|
||||
if (info.percent !== this.percent) this.percent = info.percent
|
||||
if (info.stage !== this.stage) this.stage = info.stage
|
||||
this._showProgressLegacy = true;
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
splashState.off('splash:show');
|
||||
splashState.off('splash:hide');
|
||||
@@ -187,6 +237,18 @@
|
||||
background: rgba($accent, 0.08);
|
||||
border-radius: 3rpx;
|
||||
overflow: hidden;
|
||||
|
||||
// inline 模式 (showLabel=false, showPercent=true): 进度条占主宽, 比例调整
|
||||
&--inline {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// full 模式: 原始整条进度条
|
||||
&--full {
|
||||
// 默认宽度 100% 由父容器 .splash-screen__progress 提供
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.splash-screen__progress-fill {
|
||||
@@ -200,6 +262,15 @@
|
||||
box-shadow: 0 0 12rpx rgba($accent, 0.4);
|
||||
}
|
||||
|
||||
// 新增: inline row 布局 (showLabel=false + showPercent=true)
|
||||
// 进度条和百分比在同一水平线: 进度条 + 右侧百分比
|
||||
.splash-screen__progress-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.splash-screen__progress-text {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -220,6 +291,14 @@
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-weight: 500;
|
||||
color: $accent;
|
||||
|
||||
// inline 模式: 字号略大, 与进度条同行
|
||||
&--inline {
|
||||
flex-shrink: 0;
|
||||
font-size: 24rpx;
|
||||
min-width: 72rpx;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes progress-fade-in {
|
||||
|
||||
Reference in New Issue
Block a user