feat(P4): 首页添加骨架屏,加载时显示占位动画
- 资产卡片区域:深色骨架屏匹配原有卡片风格 - 持仓列表区域:模拟卡片布局的骨架占位 - 添加 loading 状态控制,数据加载完成后切换 - 骨架屏带渐变动画效果,提升用户体验
This commit is contained in:
parent
cac6e4dfff
commit
99094eeed8
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
API 接口设计文档.md
Normal file → Executable file
0
API 接口设计文档.md
Normal file → Executable file
0
index.html
Normal file → Executable file
0
index.html
Normal file → Executable file
0
manifest.json
Normal file → Executable file
0
manifest.json
Normal file → Executable file
0
package-lock.json
generated
Normal file → Executable file
0
package-lock.json
generated
Normal file → Executable file
0
package.json
Normal file → Executable file
0
package.json
Normal file → Executable file
0
pages.json
Normal file → Executable file
0
pages.json
Normal file → Executable file
0
pages/config/config.vue
Normal file → Executable file
0
pages/config/config.vue
Normal file → Executable file
0
pages/detail/detail.vue
Normal file → Executable file
0
pages/detail/detail.vue
Normal file → Executable file
142
pages/index/index.vue
Normal file → Executable file
142
pages/index/index.vue
Normal file → Executable file
@ -1,7 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page-container">
|
<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">
|
<view class="asset-card">
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +66,28 @@
|
|||||||
<text class="section-title">当前记录组合</text>
|
<text class="section-title">当前记录组合</text>
|
||||||
</view>
|
</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
|
<view
|
||||||
|
v-else
|
||||||
v-for="holding in holdings"
|
v-for="holding in holdings"
|
||||||
:key="holding.id"
|
:key="holding.id"
|
||||||
class="holding-card"
|
class="holding-card"
|
||||||
@ -95,6 +133,9 @@ import { ref } from 'vue';
|
|||||||
import { onShow } from '@dcloudio/uni-app';
|
import { onShow } from '@dcloudio/uni-app';
|
||||||
import { api } from '../../utils/api';
|
import { api } from '../../utils/api';
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(true);
|
||||||
|
|
||||||
// 资产数据
|
// 资产数据
|
||||||
const assetData = ref({
|
const assetData = ref({
|
||||||
totalValue: 0,
|
totalValue: 0,
|
||||||
@ -171,12 +212,14 @@ const goDetail = (holdingId) => {
|
|||||||
onShow(async () => {
|
onShow(async () => {
|
||||||
console.log('首页显示,刷新数据...');
|
console.log('首页显示,刷新数据...');
|
||||||
isFetching = true;
|
isFetching = true;
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
fetchAssetData(),
|
fetchAssetData(),
|
||||||
fetchHoldingsData()
|
fetchHoldingsData()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
loading.value = false;
|
||||||
isFetching = false;
|
isFetching = false;
|
||||||
});
|
});
|
||||||
</script>
|
</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: 资产卡片样式 (精修版) */
|
/* Part 1: 资产卡片样式 (精修版) */
|
||||||
/* ============================ */
|
/* ============================ */
|
||||||
|
|||||||
0
pages/me/me.vue
Normal file → Executable file
0
pages/me/me.vue
Normal file → Executable file
0
pages/strategies/edit/edit.vue
Normal file → Executable file
0
pages/strategies/edit/edit.vue
Normal file → Executable file
0
pages/strategies/strategies.vue
Normal file → Executable file
0
pages/strategies/strategies.vue
Normal file → Executable file
0
static/home.png
Normal file → Executable file
0
static/home.png
Normal file → Executable file
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
0
static/profile_circled.png
Normal file → Executable file
0
static/profile_circled.png
Normal file → Executable file
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
0
static/puzzle.png
Normal file → Executable file
0
static/puzzle.png
Normal file → Executable file
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
0
uni.promisify.adaptor.js
Normal file → Executable file
0
uni.promisify.adaptor.js
Normal file → Executable file
0
uni_modules/uni-icons/changelog.md
Normal file → Executable file
0
uni_modules/uni-icons/changelog.md
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uni-icons.vue
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uni-icons.vue
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uniicons.css
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uniicons.css
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uniicons.ttf
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uniicons.ttf
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
Normal file → Executable file
0
uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
Normal file → Executable file
0
uni_modules/uni-icons/package.json
Normal file → Executable file
0
uni_modules/uni-icons/package.json
Normal file → Executable file
0
uni_modules/uni-icons/readme.md
Normal file → Executable file
0
uni_modules/uni-icons/readme.md
Normal file → Executable file
0
uni_modules/uni-scss/changelog.md
Normal file → Executable file
0
uni_modules/uni-scss/changelog.md
Normal file → Executable file
0
uni_modules/uni-scss/index.scss
Normal file → Executable file
0
uni_modules/uni-scss/index.scss
Normal file → Executable file
0
uni_modules/uni-scss/package.json
Normal file → Executable file
0
uni_modules/uni-scss/package.json
Normal file → Executable file
0
uni_modules/uni-scss/readme.md
Normal file → Executable file
0
uni_modules/uni-scss/readme.md
Normal file → Executable file
0
uni_modules/uni-scss/styles/index.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/index.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_border.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_border.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_color.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_color.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_radius.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_radius.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_space.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_space.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_styles.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_styles.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_text.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_text.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_variables.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/setting/_variables.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/tools/functions.scss
Normal file → Executable file
0
uni_modules/uni-scss/styles/tools/functions.scss
Normal file → Executable file
0
uni_modules/uni-scss/theme.scss
Normal file → Executable file
0
uni_modules/uni-scss/theme.scss
Normal file → Executable file
0
uni_modules/uni-scss/variables.scss
Normal file → Executable file
0
uni_modules/uni-scss/variables.scss
Normal file → Executable file
0
utils/api.js
Normal file → Executable file
0
utils/api.js
Normal file → Executable file
0
vite.config.js
Normal file → Executable file
0
vite.config.js
Normal file → Executable file
Loading…
Reference in New Issue
Block a user