feat(P4): 首页添加骨架屏,加载时显示占位动画

- 资产卡片区域:深色骨架屏匹配原有卡片风格
- 持仓列表区域:模拟卡片布局的骨架占位
- 添加 loading 状态控制,数据加载完成后切换
- 骨架屏带渐变动画效果,提升用户体验
This commit is contained in:
claw_bot 2026-03-13 03:02:33 +00:00
parent cac6e4dfff
commit 99094eeed8
47 changed files with 141 additions and 1 deletions

0
.gitignore vendored Normal file → Executable file
View File

0
API 接口设计文档.md Normal file → Executable file
View File

0
App.vue Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

0
index.html Normal file → Executable file
View File

0
main.js Normal file → Executable file
View File

0
manifest.json Normal file → Executable file
View File

0
package-lock.json generated Normal file → Executable file
View File

0
package.json Normal file → Executable file
View File

0
pages.json Normal file → Executable file
View File

0
pages/config/config.vue Normal file → Executable file
View File

0
pages/detail/detail.vue Normal file → Executable file
View File

142
pages/index/index.vue Normal file → Executable file
View File

@ -1,7 +1,24 @@
<template>
<view class="page-container">
<view class="header-section">
<!-- 骨架屏资产卡片区域 -->
<view class="header-section" v-if="loading">
<view class="skeleton-asset-card">
<view class="skeleton-row">
<view class="skeleton-text skeleton-label"></view>
</view>
<view class="skeleton-row">
<view class="skeleton-text skeleton-big"></view>
</view>
<view class="skeleton-row skeleton-bottom">
<view class="skeleton-text skeleton-stat"></view>
<view class="skeleton-text skeleton-stat"></view>
</view>
</view>
</view>
<!-- 真实内容资产卡片 -->
<view class="header-section" v-else>
<view class="asset-card">
@ -49,7 +66,28 @@
<text class="section-title">当前记录组合</text>
</view>
<!-- 骨架屏持仓卡片 -->
<view v-if="loading" class="holding-card" v-for="i in 2" :key="'skeleton-' + i">
<view class="card-top">
<view class="flex-row items-center gap-2">
<view class="skeleton-icon"></view>
<view class="flex-col">
<view class="skeleton-text skeleton-name"></view>
<view class="skeleton-text skeleton-tags"></view>
</view>
</view>
<view class="skeleton-text skeleton-status"></view>
</view>
<view class="card-divider"></view>
<view class="card-bottom">
<view class="skeleton-text skeleton-data"></view>
<view class="skeleton-text skeleton-data"></view>
</view>
</view>
<!-- 真实内容持仓卡片 -->
<view
v-else
v-for="holding in holdings"
:key="holding.id"
class="holding-card"
@ -95,6 +133,9 @@ import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { api } from '../../utils/api';
//
const loading = ref(true);
//
const assetData = ref({
totalValue: 0,
@ -171,12 +212,14 @@ const goDetail = (holdingId) => {
onShow(async () => {
console.log('首页显示,刷新数据...');
isFetching = true;
loading.value = true;
await Promise.all([
fetchAssetData(),
fetchHoldingsData()
]);
loading.value = false;
isFetching = false;
});
</script>
@ -243,6 +286,103 @@ onShow(async () => {
/* 跌 */
/* ============================ */
/* 骨架屏样式 */
/* ============================ */
.skeleton-asset-card {
background-color: #064E3B;
border-radius: 40rpx;
padding: 40rpx 48rpx;
min-height: 320rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.skeleton-row {
display: flex;
align-items: center;
}
.skeleton-bottom {
justify-content: space-between;
}
.skeleton-text {
background: linear-gradient(90deg, rgba(255,255,255,0.1) 25%, rgba(255,255,255,0.2) 37%, rgba(255,255,255,0.1) 50%);
background-size: 400% 100%;
animation: skeleton-loading 1.8s ease infinite;
border-radius: 8rpx;
}
.skeleton-label {
width: 200rpx;
height: 28rpx;
}
.skeleton-big {
width: 400rpx;
height: 68rpx;
margin-top: 20rpx;
}
.skeleton-stat {
width: 180rpx;
height: 36rpx;
}
.skeleton-icon {
width: 80rpx;
height: 80rpx;
border-radius: 20rpx;
background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
background-size: 400% 100%;
animation: skeleton-loading 1.8s ease infinite;
}
.skeleton-name {
width: 160rpx;
height: 30rpx;
margin-bottom: 8rpx;
background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
background-size: 400% 100%;
animation: skeleton-loading 1.8s ease infinite;
}
.skeleton-tags {
width: 100rpx;
height: 22rpx;
background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
background-size: 400% 100%;
animation: skeleton-loading 1.8s ease infinite;
}
.skeleton-status {
width: 100rpx;
height: 32rpx;
border-radius: 100rpx;
background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
background-size: 400% 100%;
animation: skeleton-loading 1.8s ease infinite;
}
.skeleton-data {
width: 140rpx;
height: 32rpx;
background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
background-size: 400% 100%;
animation: skeleton-loading 1.8s ease infinite;
}
@keyframes skeleton-loading {
0% {
background-position: 100% 50%
}
100% {
background-position: 0 50%
}
}
/* ============================ */
/* Part 1: 资产卡片样式 (精修版) */
/* ============================ */

0
pages/me/me.vue Normal file → Executable file
View File

0
pages/strategies/edit/edit.vue Normal file → Executable file
View File

0
pages/strategies/strategies.vue Normal file → Executable file
View File

0
static/home.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

0
static/profile_circled.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

0
static/puzzle.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

0
uni.promisify.adaptor.js Normal file → Executable file
View File

0
uni.scss Normal file → Executable file
View File

0
uni_modules/uni-icons/changelog.md Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

0
uni_modules/uni-icons/package.json Normal file → Executable file
View File

0
uni_modules/uni-icons/readme.md Normal file → Executable file
View File

0
uni_modules/uni-scss/changelog.md Normal file → Executable file
View File

0
uni_modules/uni-scss/index.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/package.json Normal file → Executable file
View File

0
uni_modules/uni-scss/readme.md Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/index.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/setting/_border.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/setting/_color.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/setting/_radius.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/setting/_space.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/setting/_styles.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/setting/_text.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/setting/_variables.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/styles/tools/functions.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/theme.scss Normal file → Executable file
View File

0
uni_modules/uni-scss/variables.scss Normal file → Executable file
View File

0
utils/api.js Normal file → Executable file
View File

0
vite.config.js Normal file → Executable file
View File