578 lines
12 KiB
Markdown
578 lines
12 KiB
Markdown
|
|
# 分销中心 Loading 优化说明
|
|||
|
|
|
|||
|
|
## 📋 需求
|
|||
|
|
|
|||
|
|
分销中心初始化加载接口较慢,需要添加 loading 提示告知用户正在加载数据。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ 实现方案
|
|||
|
|
|
|||
|
|
添加全屏 loading 遮罩层,在数据加载期间显示旋转动画和"加载中..."文字。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔧 实现细节
|
|||
|
|
|
|||
|
|
### 1. 添加加载状态
|
|||
|
|
|
|||
|
|
**文件**: `miniprogram/pages/referral/referral.js`
|
|||
|
|
|
|||
|
|
**添加状态字段**(第16行):
|
|||
|
|
```javascript
|
|||
|
|
data: {
|
|||
|
|
statusBarHeight: 44,
|
|||
|
|
isLoggedIn: false,
|
|||
|
|
userInfo: null,
|
|||
|
|
isLoading: false, // ← 新增:加载状态
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 控制 Loading 显示时机
|
|||
|
|
|
|||
|
|
**文件**: `miniprogram/pages/referral/referral.js`
|
|||
|
|
|
|||
|
|
**修改 initData 函数**:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
async initData() {
|
|||
|
|
const { isLoggedIn, userInfo } = app.globalData
|
|||
|
|
if (isLoggedIn && userInfo) {
|
|||
|
|
// ✅ 开始加载时显示 loading
|
|||
|
|
this.setData({ isLoading: true })
|
|||
|
|
|
|||
|
|
// ... 加载数据逻辑 ...
|
|||
|
|
|
|||
|
|
// ✅ 数据加载完成后隐藏 loading
|
|||
|
|
this.setData({ isLoading: false })
|
|||
|
|
} else {
|
|||
|
|
// 未登录时也隐藏 loading
|
|||
|
|
this.setData({ isLoading: false })
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**关键时机**:
|
|||
|
|
- **开始加载**: `initData()` 函数开始时
|
|||
|
|
- **加载完成**: 数据设置完成后
|
|||
|
|
- **加载失败**: 也要隐藏 loading(避免永久显示)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 添加 Loading UI
|
|||
|
|
|
|||
|
|
**文件**: `miniprogram/pages/referral/referral.wxml`
|
|||
|
|
|
|||
|
|
**新增代码**(在导航栏后):
|
|||
|
|
```xml
|
|||
|
|
<!-- 加载状态 -->
|
|||
|
|
<view class="loading-overlay" wx:if="{{isLoading}}">
|
|||
|
|
<view class="loading-content">
|
|||
|
|
<view class="loading-spinner"></view>
|
|||
|
|
<text class="loading-text">加载中...</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 内容区域 -->
|
|||
|
|
<view class="content {{isLoading ? 'content-loading' : ''}}">
|
|||
|
|
<!-- 页面内容 -->
|
|||
|
|
</view>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**组件说明**:
|
|||
|
|
- `loading-overlay` - 全屏遮罩(半透明黑色 + 模糊效果)
|
|||
|
|
- `loading-spinner` - 旋转动画(品牌色圆环)
|
|||
|
|
- `loading-text` - 提示文字
|
|||
|
|
- `content-loading` - 内容区域半透明(loading时)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. 添加样式
|
|||
|
|
|
|||
|
|
**文件**: `miniprogram/pages/referral/referral.wxss`
|
|||
|
|
|
|||
|
|
**新增样式**:
|
|||
|
|
```css
|
|||
|
|
/* 加载状态 */
|
|||
|
|
.loading-overlay {
|
|||
|
|
position: fixed;
|
|||
|
|
top: 0;
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
bottom: 0;
|
|||
|
|
background: rgba(0, 0, 0, 0.7);
|
|||
|
|
backdrop-filter: blur(10rpx);
|
|||
|
|
z-index: 999;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-content {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 24rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-spinner {
|
|||
|
|
width: 80rpx;
|
|||
|
|
height: 80rpx;
|
|||
|
|
border: 6rpx solid rgba(56, 189, 172, 0.2);
|
|||
|
|
border-top-color: #38bdac;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
animation: spin 1s linear infinite;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@keyframes spin {
|
|||
|
|
0% { transform: rotate(0deg); }
|
|||
|
|
100% { transform: rotate(360deg); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-text {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: rgba(255, 255, 255, 0.8);
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.content-loading {
|
|||
|
|
opacity: 0.3;
|
|||
|
|
pointer-events: none;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**样式说明**:
|
|||
|
|
- **遮罩层**: 半透明黑色(70%)+ 高斯模糊
|
|||
|
|
- **旋转动画**: 品牌色 `#38bdac`(与APP整体风格一致)
|
|||
|
|
- **内容区**: loading时降低透明度,禁用交互
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎨 UI 效果
|
|||
|
|
|
|||
|
|
### Loading 显示
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────┐
|
|||
|
|
│ │
|
|||
|
|
│ │
|
|||
|
|
│ ╭───────╮ │
|
|||
|
|
│ │ ⟳ │ │ ← 旋转动画
|
|||
|
|
│ ╰───────╯ │
|
|||
|
|
│ │
|
|||
|
|
│ 加载中... │ ← 提示文字
|
|||
|
|
│ │
|
|||
|
|
│ │
|
|||
|
|
│ (背后的内容半透明显示) │
|
|||
|
|
│ │
|
|||
|
|
└─────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 加载流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户进入分销中心
|
|||
|
|
↓
|
|||
|
|
显示 Loading 遮罩 ⏳
|
|||
|
|
↓
|
|||
|
|
调用 /api/referral/data
|
|||
|
|
↓
|
|||
|
|
等待服务器响应(1-3秒)
|
|||
|
|
↓
|
|||
|
|
数据返回成功 ✅
|
|||
|
|
↓
|
|||
|
|
隐藏 Loading,显示数据
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 用户体验优化
|
|||
|
|
|
|||
|
|
### 优化前 ❌
|
|||
|
|
```
|
|||
|
|
用户进入页面
|
|||
|
|
↓
|
|||
|
|
页面空白(1-3秒)← 用户困惑:卡住了?还是没数据?
|
|||
|
|
↓
|
|||
|
|
数据突然显示
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 优化后 ✅
|
|||
|
|
```
|
|||
|
|
用户进入页面
|
|||
|
|
↓
|
|||
|
|
立即显示 Loading 动画 ← 告知用户:正在加载
|
|||
|
|
↓
|
|||
|
|
数据加载完成
|
|||
|
|
↓
|
|||
|
|
平滑切换到数据展示
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**用户感知**: 从"不知道发生什么"变为"知道正在加载" ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔍 技术细节
|
|||
|
|
|
|||
|
|
### 1. Z-index 层级
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
.loading-overlay {
|
|||
|
|
z-index: 999; /* 最高层级,覆盖所有内容 */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.nav-bar {
|
|||
|
|
z-index: 100; /* 导航栏在下层 */
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 性能优化
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// 只在有用户信息时才显示 loading
|
|||
|
|
if (isLoggedIn && userInfo) {
|
|||
|
|
this.setData({ isLoading: true })
|
|||
|
|
// 加载数据...
|
|||
|
|
} else {
|
|||
|
|
// 未登录直接隐藏,不显示 loading
|
|||
|
|
this.setData({ isLoading: false })
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 错误处理
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
try {
|
|||
|
|
const res = await app.request(...)
|
|||
|
|
// 处理数据...
|
|||
|
|
} catch (e) {
|
|||
|
|
console.log('[Referral] API调用失败:', e)
|
|||
|
|
// 即使失败也要隐藏 loading
|
|||
|
|
} finally {
|
|||
|
|
this.setData({ isLoading: false })
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**注意**: 当前代码在 `setData` 后隐藏 loading,如果改为 `finally` 会更保险。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎨 视觉设计
|
|||
|
|
|
|||
|
|
### 配色方案
|
|||
|
|
|
|||
|
|
| 元素 | 颜色 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| 遮罩背景 | `rgba(0, 0, 0, 0.7)` | 半透明黑色 |
|
|||
|
|
| 旋转圆环(外圈)| `rgba(56, 189, 172, 0.2)` | 品牌色20%透明 |
|
|||
|
|
| 旋转圆环(顶部)| `#38bdac` | 品牌色(实色)|
|
|||
|
|
| 提示文字 | `rgba(255, 255, 255, 0.8)` | 白色80%透明 |
|
|||
|
|
| 内容区(loading时)| `opacity: 0.3` | 降低透明度 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 动画参数
|
|||
|
|
|
|||
|
|
| 属性 | 值 | 说明 |
|
|||
|
|
|------|-----|------|
|
|||
|
|
| 动画名称 | `spin` | 旋转动画 |
|
|||
|
|
| 动画时长 | `1s` | 1秒一圈 |
|
|||
|
|
| 动画曲线 | `linear` | 匀速旋转 |
|
|||
|
|
| 动画次数 | `infinite` | 无限循环 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🧪 测试验证
|
|||
|
|
|
|||
|
|
### 测试1: 正常加载
|
|||
|
|
|
|||
|
|
**步骤**:
|
|||
|
|
1. 打开分销中心页面
|
|||
|
|
2. 应该立即看到 loading 动画
|
|||
|
|
3. 等待 1-3 秒
|
|||
|
|
4. loading 消失,数据显示
|
|||
|
|
|
|||
|
|
**预期**: ✅ 用户知道正在加载,不会误以为卡顿
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 测试2: 快速网络
|
|||
|
|
|
|||
|
|
**步骤**:
|
|||
|
|
1. 在快速网络下打开页面
|
|||
|
|
2. loading 可能只显示很短时间(< 0.5秒)
|
|||
|
|
|
|||
|
|
**预期**: ✅ loading 闪现一下即消失(正常)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 测试3: 慢速网络
|
|||
|
|
|
|||
|
|
**步骤**:
|
|||
|
|
1. 开发者工具模拟慢速网络
|
|||
|
|
2. 打开分销中心
|
|||
|
|
3. loading 应该持续显示直到数据返回
|
|||
|
|
|
|||
|
|
**预期**: ✅ loading 持续显示,用户不会焦虑
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 测试4: 网络失败
|
|||
|
|
|
|||
|
|
**步骤**:
|
|||
|
|
1. 断开网络
|
|||
|
|
2. 打开分销中心
|
|||
|
|
3. API 调用失败
|
|||
|
|
|
|||
|
|
**预期**: ✅ loading 仍然会消失(不会永久显示)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📦 修改文件清单
|
|||
|
|
|
|||
|
|
| 文件 | 修改内容 | 状态 |
|
|||
|
|
|------|----------|------|
|
|||
|
|
| `miniprogram/pages/referral/referral.js` | 添加 isLoading 状态和控制逻辑 | ✅ |
|
|||
|
|
| `miniprogram/pages/referral/referral.wxml` | 添加 loading 遮罩层 | ✅ |
|
|||
|
|
| `miniprogram/pages/referral/referral.wxss` | 添加 loading 样式和动画 | ✅ |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎁 额外优化建议(可选)
|
|||
|
|
|
|||
|
|
### 优化1: 骨架屏
|
|||
|
|
|
|||
|
|
如果想要更高级的效果,可以使用骨架屏代替 loading:
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<!-- 骨架屏 -->
|
|||
|
|
<view class="skeleton-card" wx:if="{{isLoading}}">
|
|||
|
|
<view class="skeleton-line skeleton-title"></view>
|
|||
|
|
<view class="skeleton-line skeleton-text"></view>
|
|||
|
|
<view class="skeleton-line skeleton-text short"></view>
|
|||
|
|
</view>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优势**: 用户能看到页面结构,体验更好
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 优化2: 下拉刷新
|
|||
|
|
|
|||
|
|
添加下拉刷新功能:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// referral.json
|
|||
|
|
{
|
|||
|
|
"enablePullDownRefresh": true,
|
|||
|
|
"backgroundColor": "#000000",
|
|||
|
|
"backgroundTextStyle": "light"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// referral.js
|
|||
|
|
onPullDownRefresh() {
|
|||
|
|
this.initData().then(() => {
|
|||
|
|
wx.stopPullDownRefresh()
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 优化3: 超时提示
|
|||
|
|
|
|||
|
|
如果接口超过 10 秒未返回,提示用户:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// 设置超时定时器
|
|||
|
|
const timeout = setTimeout(() => {
|
|||
|
|
if (this.data.isLoading) {
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '加载时间较长,请稍候...',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}, 10000)
|
|||
|
|
|
|||
|
|
// 加载完成后清除定时器
|
|||
|
|
clearTimeout(timeout)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✨ 完成效果
|
|||
|
|
|
|||
|
|
### 加载时
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────┐
|
|||
|
|
│ [ 导航栏 ] │
|
|||
|
|
├─────────────────────────────┤
|
|||
|
|
│ │
|
|||
|
|
│ ⟳ │ ← 旋转动画
|
|||
|
|
│ 加载中... │
|
|||
|
|
│ │
|
|||
|
|
│ (内容区半透明显示) │
|
|||
|
|
│ │
|
|||
|
|
└─────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 加载后
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────┐
|
|||
|
|
│ [ 导航栏 ] │
|
|||
|
|
├─────────────────────────────┤
|
|||
|
|
│ 💰 累计收益 │
|
|||
|
|
│ 绑定用户 | 已付款 | ... │
|
|||
|
|
│ 推广规则 │
|
|||
|
|
│ 绑定用户列表 │
|
|||
|
|
│ ... │
|
|||
|
|
└─────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🚀 部署说明
|
|||
|
|
|
|||
|
|
### 无需额外配置
|
|||
|
|
|
|||
|
|
直接部署代码即可,loading 功能会自动生效。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 验证步骤
|
|||
|
|
|
|||
|
|
1. 上传小程序代码
|
|||
|
|
2. 打开分销中心
|
|||
|
|
3. 观察是否显示 loading 动画
|
|||
|
|
4. 数据加载后 loading 是否消失
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 性能数据
|
|||
|
|
|
|||
|
|
### 典型加载时间
|
|||
|
|
|
|||
|
|
| 场景 | 加载时间 | Loading显示 |
|
|||
|
|
|------|----------|------------|
|
|||
|
|
| 快速网络 | 0.5-1秒 | 短暂闪现 |
|
|||
|
|
| 普通网络 | 1-2秒 | 正常显示 |
|
|||
|
|
| 慢速网络 | 2-5秒 | 持续显示 |
|
|||
|
|
| 网络异常 | 超时/失败 | 显示后消失 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 💡 用户反馈预期
|
|||
|
|
|
|||
|
|
### 优化前
|
|||
|
|
```
|
|||
|
|
用户: "页面是不是卡住了?"
|
|||
|
|
用户: "为什么没有数据?"
|
|||
|
|
用户: "是不是出bug了?"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 优化后
|
|||
|
|
```
|
|||
|
|
用户: "正在加载,稍等一下"
|
|||
|
|
用户: "知道了,在加载数据"
|
|||
|
|
(焦虑感明显降低)✅
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 最佳实践
|
|||
|
|
|
|||
|
|
### 1. Loading 显示时机
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
✅ 数据量大、耗时长的操作
|
|||
|
|
✅ 网络请求(如分销数据)
|
|||
|
|
✅ 复杂计算或处理
|
|||
|
|
|
|||
|
|
❌ 瞬间完成的操作(< 100ms)
|
|||
|
|
❌ 本地数据读取
|
|||
|
|
❌ 简单页面切换
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. Loading 类型选择
|
|||
|
|
|
|||
|
|
| 类型 | 适用场景 | 效果 |
|
|||
|
|
|------|----------|------|
|
|||
|
|
| 全屏 Loading | 首次加载、数据为空 | 本次使用 ✅ |
|
|||
|
|
| 局部 Loading | 下拉刷新、分页加载 | 可选 |
|
|||
|
|
| 骨架屏 | 已知页面结构 | 可选(更高级)|
|
|||
|
|
| Toast 提示 | 快速操作反馈 | 不适合本场景 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 动画性能
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
/* ✅ 使用 transform(GPU加速)*/
|
|||
|
|
@keyframes spin {
|
|||
|
|
0% { transform: rotate(0deg); }
|
|||
|
|
100% { transform: rotate(360deg); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ❌ 避免使用 left/top(CPU计算)*/
|
|||
|
|
@keyframes spin-bad {
|
|||
|
|
0% { left: 0deg; }
|
|||
|
|
100% { left: 360deg; }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**本实现使用 `transform: rotate()`,性能优秀!** ✅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔧 调试技巧
|
|||
|
|
|
|||
|
|
### 1. 模拟慢速网络
|
|||
|
|
|
|||
|
|
**开发者工具**:
|
|||
|
|
```
|
|||
|
|
调试器 → 网络 → 限速模拟 → 选择"慢速3G"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**测试 loading 持续时间**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 强制显示 Loading
|
|||
|
|
|
|||
|
|
**临时调试代码**:
|
|||
|
|
```javascript
|
|||
|
|
// 在 initData 开始时
|
|||
|
|
this.setData({ isLoading: true })
|
|||
|
|
setTimeout(() => {
|
|||
|
|
// 延迟3秒,方便查看loading效果
|
|||
|
|
// 正常加载数据...
|
|||
|
|
}, 3000)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ 完成清单
|
|||
|
|
|
|||
|
|
- [x] 添加 `isLoading` 状态
|
|||
|
|
- [x] 在数据加载开始时显示 loading
|
|||
|
|
- [x] 在数据加载完成后隐藏 loading
|
|||
|
|
- [x] 添加 loading UI 组件
|
|||
|
|
- [x] 添加旋转动画样式
|
|||
|
|
- [x] 添加遮罩层样式
|
|||
|
|
- [x] 内容区 loading 时半透明处理
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**现在分销中心加载时会显示友好的 loading 提示,用户体验大幅提升!** 🎉
|