refactor(splash-screen): 重构启动屏UI与动画逻辑
重写启动屏的模板结构与样式,替换原有简单logo加载动画为带光晕、轨道粒子的全新动效,优化过渡动画时长与曲线,简化冗余的生命周期注释代码
This commit is contained in:
@@ -1,16 +1,25 @@
|
||||
<template>
|
||||
<!-- #ifndef APP-PLUS -->
|
||||
<view v-if="visible" class="splash-screen" :class="{ 'splash-screen--leaving': leaving }">
|
||||
<view class="splash-screen__bg"></view>
|
||||
<view class="splash-screen__content">
|
||||
<view class="splash-screen__logo">
|
||||
<view class="splash-screen__logo-inner">S</view>
|
||||
<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__name">Shop</view>
|
||||
<view class="splash-screen__loader">
|
||||
<view class="splash-screen__dot"></view>
|
||||
<view class="splash-screen__dot"></view>
|
||||
<view class="splash-screen__dot"></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>
|
||||
@@ -29,14 +38,10 @@
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 1) 启动时同步读取状态 (防止 mount 前已经 hide 的情况)
|
||||
if (splashState.isShow()) {
|
||||
this.visible = true;
|
||||
}
|
||||
// 2) 通知 state 模块: 组件已 mount
|
||||
// 如果此时 splashState 有 _pendingHide (软隐藏), 会触发真关
|
||||
splashState.notifyMounted();
|
||||
// 3) 监听后续事件
|
||||
splashState.on('splash:show', () => {
|
||||
this.visible = true;
|
||||
this.leaving = false;
|
||||
@@ -56,19 +61,28 @@
|
||||
},
|
||||
methods: {
|
||||
_leave() {
|
||||
// 触发淡出动画,动画结束再 unmount
|
||||
this.leaving = true;
|
||||
if (this._leaveTimer) clearTimeout(this._leaveTimer);
|
||||
this._leaveTimer = setTimeout(() => {
|
||||
this.visible = false;
|
||||
this.leaving = false;
|
||||
}, 320);
|
||||
}, 480);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// ============================================================
|
||||
// 启动屏 — 极光脉冲
|
||||
// 中心柔光球呼吸, 三圈粒子轨道旋转, 整体白底 + 蓝紫辉光
|
||||
// 单一焦点 / 对称结构 / 黄金比例节奏, 跨平台一致
|
||||
// ============================================================
|
||||
|
||||
$accent: #6366F1; // 主色: 靛蓝
|
||||
$accent-light: #A5B4FC; // 亮部
|
||||
$accent-deep: #4338CA; // 暗部
|
||||
|
||||
.splash-screen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@@ -79,100 +93,222 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ffffff;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s ease;
|
||||
transition: opacity 0.45s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&--leaving {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.splash-screen__bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f7f7f7 100%);
|
||||
}
|
||||
|
||||
.splash-screen__content {
|
||||
// 容器: 480rpx 见方, 居中
|
||||
.splash-screen__field {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.splash-screen__logo {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 24rpx;
|
||||
background: #FF0036;
|
||||
width: 480rpx;
|
||||
height: 480rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 8rpx 24rpx rgba(255, 0, 54, 0.18);
|
||||
animation: splash-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
|
||||
// 入场: 缩放 + 透明度, 弹性曲线
|
||||
animation: field-enter 0.8s cubic-bezier(0.34, 1.4, 0.64, 1) both;
|
||||
}
|
||||
|
||||
.splash-screen__logo-inner {
|
||||
color: #fff;
|
||||
font-size: 56rpx;
|
||||
font-weight: 700;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
|
||||
.splash-screen__name {
|
||||
margin-top: 28rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.splash-screen__loader {
|
||||
margin-top: 48rpx;
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.splash-screen__dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
// 中心大光晕: 覆盖整个 field, 营造氛围
|
||||
.splash-screen__aura {
|
||||
position: absolute;
|
||||
width: 480rpx;
|
||||
height: 480rpx;
|
||||
border-radius: 50%;
|
||||
background: #FF0036;
|
||||
opacity: 0.4;
|
||||
animation: splash-bounce 1.2s ease-in-out infinite;
|
||||
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;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
animation-delay: 0.15s;
|
||||
// 中心星核
|
||||
.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%,
|
||||
$accent-deep 100%);
|
||||
box-shadow:
|
||||
0 0 24rpx rgba($accent, 0.6),
|
||||
0 0 48rpx rgba($accent, 0.3),
|
||||
inset -2rpx -3rpx 6rpx rgba($accent-deep, 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;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
animation-delay: 0.3s;
|
||||
&--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;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes splash-pop {
|
||||
// 粒子: 沿轨道运动, 起始位置在轨道顶部
|
||||
.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% {
|
||||
transform: scale(0.6);
|
||||
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 splash-bounce {
|
||||
0%, 80%, 100% {
|
||||
transform: scale(0.7);
|
||||
opacity: 0.4;
|
||||
}
|
||||
40% {
|
||||
// 中心星核呼吸
|
||||
@keyframes core-pulse {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
opacity: 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>
|
||||
|
||||
Reference in New Issue
Block a user