Files
lucky_shop/components/splash-screen/splash-screen.vue
ZF sun 3f09dca054 refactor(splash-screen): 移除废弃的启动屏配置系统
简化启动屏组件代码,删除不再使用的splashConfig全局配置、相关工具方法和冗余的布局逻辑,统一进度条展示样式。
2026-07-13 10:22:45 +08:00

359 lines
7.6 KiB
Vue

<template>
<!-- #ifndef APP-PLUS -->
<view v-if="visible" class="splash-screen" :class="{ 'splash-screen--leaving': leaving }">
<view class="splash-screen__field">
<view class="splash-screen__aura"></view>
<view class="splash-screen__orbit splash-screen__orbit--1">
<view class="splash-screen__particle splash-screen__particle--1"></view>
</view>
<view class="splash-screen__orbit splash-screen__orbit--2">
<view class="splash-screen__particle splash-screen__particle--2"></view>
</view>
<view class="splash-screen__orbit splash-screen__orbit--3">
<view class="splash-screen__particle splash-screen__particle--3"></view>
</view>
<view class="splash-screen__core">
<view class="splash-screen__core-halo"></view>
<view class="splash-screen__core-body"></view>
</view>
</view>
<!-- 进度条 + 百分比 -->
<view class="splash-screen__progress">
<text class="splash-screen__progress-percent">{{ percent }}%</text>
<view class="splash-screen__progress-bar">
<view class="splash-screen__progress-fill" :style="{ width: percent + '%' }"></view>
</view>
</view>
</view>
<!-- #endif -->
</template>
<script>
import splashState from '@/common/js/splash-state.js';
export default {
name: 'splash-screen',
data() {
return {
visible: true,
leaving: false,
percent: 0,
};
},
created() {
try {
const init = splashState.getProgress()
this.percent = init.percent
} catch (e) {}
if (!splashState.isShow()) {
this.visible = false
}
},
mounted() {
splashState.notifyMounted();
splashState.on('splash:show', () => {
this.visible = true;
this.leaving = false;
const init = splashState.getProgress()
if (init.percent > this.percent) this.percent = init.percent
});
splashState.on('splash:hide', (info) => {
if (this.percent < 100) {
this.percent = 100;
}
const fast = info && info.mode === 'fast'
this._leave(fast)
});
splashState.onProgress((info) => {
if (info.percent !== this.percent) this.percent = info.percent
});
},
beforeDestroy() {
splashState.off('splash:show');
splashState.off('splash:hide');
splashState.offProgress();
splashState.notifyUnmounted();
if (this._leaveTimer) {
clearTimeout(this._leaveTimer);
this._leaveTimer = null;
}
},
methods: {
_leave(fast) {
this.leaving = true;
if (this._leaveTimer) clearTimeout(this._leaveTimer);
const delay = fast ? 80 : 480
this._leaveTimer = setTimeout(() => {
this.visible = false;
this.leaving = false;
}, delay);
}
}
};
</script>
<style lang="scss" scoped>
$accent: #6366F1;
$accent-light: #A5B4FC;
.splash-screen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 99999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #ffffff;
overflow: hidden;
opacity: 1;
transition: opacity 0.45s cubic-bezier(0.4, 0, 0.2, 1);
&--leaving {
opacity: 0;
}
}
.splash-screen__progress {
position: absolute;
bottom: 120rpx;
left: 50%;
transform: translateX(-50%);
width: 480rpx;
max-width: 80vw;
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
opacity: 0;
animation: progress-fade-in 0.2s ease-out 0.1s forwards;
}
.splash-screen__progress-bar {
position: relative;
width: 100%;
height: 4rpx;
background: rgba($accent, 0.08);
border-radius: 2rpx;
overflow: hidden;
}
.splash-screen__progress-fill {
position: absolute;
top: 0;
left: 0;
height: 100%;
background: linear-gradient(90deg, $accent-light, $accent);
border-radius: 2rpx;
transition: width 0.45s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 0 12rpx rgba($accent, 0.4);
}
.splash-screen__progress-percent {
font-size: 24rpx;
font-variant-numeric: tabular-nums;
font-weight: 500;
color: $accent;
}
@keyframes progress-fade-in {
from { opacity: 0; transform: translateX(-50%) translateY(20rpx); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.splash-screen__field {
position: relative;
width: 480rpx;
height: 480rpx;
display: flex;
align-items: center;
justify-content: center;
animation: field-enter 0.4s cubic-bezier(0.34, 1.4, 0.64, 1) both;
}
.splash-screen__aura {
position: absolute;
width: 480rpx;
height: 480rpx;
border-radius: 50%;
background: radial-gradient(circle,
rgba($accent-light, 0.35) 0%,
rgba($accent, 0.18) 25%,
rgba($accent, 0.05) 50%,
rgba($accent, 0) 75%);
box-shadow: 0 0 200rpx rgba($accent, 0.15);
animation: aura-breathe 3.6s ease-in-out infinite;
}
.splash-screen__core {
position: relative;
width: 36rpx;
height: 36rpx;
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
animation: core-pulse 2.4s ease-in-out infinite;
}
.splash-screen__core-halo {
position: absolute;
width: 120rpx;
height: 120rpx;
border-radius: 50%;
background: radial-gradient(circle,
rgba($accent, 0.5) 0%,
rgba($accent, 0) 60%);
animation: halo-expand 2.4s ease-in-out infinite;
}
.splash-screen__core-body {
position: relative;
width: 36rpx;
height: 36rpx;
border-radius: 50%;
background: radial-gradient(circle at 35% 30%,
#EEF2FF 0%,
$accent-light 35%,
$accent 70%,
#4338CA 100%);
box-shadow:
0 0 24rpx rgba($accent, 0.6),
0 0 48rpx rgba($accent, 0.3),
inset -2rpx -3rpx 6rpx rgba(#4338CA, 0.5),
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.5);
}
.splash-screen__orbit {
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
pointer-events: none;
transform-origin: center;
&--1 {
width: 160rpx;
height: 160rpx;
margin-top: -80rpx;
margin-left: -80rpx;
border: 1rpx solid rgba($accent, 0.18);
animation: orbit-rotate 6s linear infinite;
}
&--2 {
width: 260rpx;
height: 260rpx;
margin-top: -130rpx;
margin-left: -130rpx;
border: 1rpx solid rgba($accent, 0.1);
animation: orbit-rotate 10s linear infinite reverse;
}
&--3 {
width: 360rpx;
height: 360rpx;
margin-top: -180rpx;
margin-left: -180rpx;
border: 1rpx solid rgba($accent, 0.06);
animation: orbit-rotate 16s linear infinite;
}
}
.splash-screen__particle {
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%,
#EEF2FF 0%,
$accent-light 40%,
$accent 100%);
&--1 {
width: 18rpx;
height: 18rpx;
margin-top: -9rpx;
margin-left: -9rpx;
transform: translateY(-80rpx);
box-shadow:
0 0 24rpx rgba($accent, 0.7),
0 0 8rpx rgba(255, 255, 255, 0.6);
}
&--2 {
width: 14rpx;
height: 14rpx;
margin-top: -7rpx;
margin-left: -7rpx;
transform: translateY(-130rpx);
box-shadow:
0 0 18rpx rgba($accent, 0.5),
0 0 4rpx rgba(255, 255, 255, 0.5);
}
&--3 {
width: 10rpx;
height: 10rpx;
margin-top: -5rpx;
margin-left: -5rpx;
transform: translateY(-180rpx);
box-shadow: 0 0 14rpx rgba($accent, 0.4);
}
}
@keyframes field-enter {
0% {
opacity: 0;
transform: scale(0.85);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@keyframes aura-breathe {
0%, 100% {
transform: scale(1);
opacity: 0.85;
}
50% {
transform: scale(1.08);
opacity: 1;
}
}
@keyframes core-pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
}
@keyframes halo-expand {
0%, 100% {
transform: scale(1);
opacity: 0.7;
}
50% {
transform: scale(1.5);
opacity: 0.3;
}
}
@keyframes orbit-rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>