Files
steel_prices_service/Sale/pages/index/PAGINATION_README.md
2026-01-07 10:13:21 +08:00

11 KiB
Raw Permalink Blame History

分页加载功能实现说明

📋 功能概述

已为价格查询页面实现触底自动加载更多功能,解决了只能展示 100 条数据的限制。

核心特性

1. 智能分页

  • 首屏加载 20 条数据(快速响应)
  • 每次滚动到底部自动加载下一页20 条)
  • 支持加载任意数量的数据4000+ 条无压力)

2. 加载状态提示

  • 加载中:显示圆形加载动画 + "加载中..." 文字
  • 继续滚动:显示蓝色闪烁提示"继续滚动加载更多"
  • 已加载全部:显示灰色"已加载全部数据"

3. 数据统计

  • 实时显示"共找到 X 条结果,已加载 Y 条"
  • 用户清楚知道当前加载进度

4. 防重复加载

  • 智能判断:正在加载时不重复触发
  • 自动检测:已加载全部数据后不再请求

🎯 实现方案

方案选择:触底加载 + 状态提示

优势:

  • 用户体验好,无需手动点击
  • 符合移动端操作习惯
  • 代码简洁,维护方便
  • 性能优秀,按需加载

工作流程:

用户查询 → 加载第1页20条
         ↓
    滚动查看数据
         ↓
    触底触发 onReachBottom()
         ↓
    自动加载第2页20条
         ↓
    追加到现有列表
         ↓
    重复直到加载全部数据

🔧 技术实现

1. 状态管理 (index.js:5-83)

data: {
  // 分页参数
  currentPage: 1,        // 当前页码
  pageSize: 20,          // 每页数量优化为20首屏更快
  hasMore: true,         // 是否还有更多数据
  loadingMore: false,    // 加载更多状态

  // 数据列表
  priceList: [],         // 价格数据列表(累加)
  total: 0,              // 总数据量
}

2. 首次查询 (index.js:216-301)

async onSearch() {
  // 重置分页状态
  this.setData({
    currentPage: 1,
    priceList: [],
    hasMore: true
  })

  // 请求第1页数据
  const searchParams = {
    region: selectedRegion,
    page: 1,
    pageSize: 20  // 关键:使用分页参数
  }

  const searchResult = await api.searchPrices(searchParams)
  this.processSearchResult(searchResult, statsResult)
}

3. 触底加载 (index.js:348-402)

async onReachBottom() {
  const { loading, loadingMore, hasMore, searched, total, priceList } = this.data

  // 防重复加载
  if (loading || loadingMore || !hasMore || !searched) {
    return
  }

  // 已加载全部数据
  if (priceList.length >= total) {
    this.setData({ hasMore: false })
    return
  }

  // 加载下一页
  this.setData({
    loadingMore: true,
    currentPage: this.data.currentPage + 1
  })

  const searchParams = {
    region: this.data.selectedRegion,
    page: this.data.currentPage,  // 下一页页码
    pageSize: 20
  }

  const searchResult = await api.searchPrices(searchParams)
  this.processSearchResult(searchResult, { data: this.data.stats })
}

4. 数据处理 (index.js:306-343)

processSearchResult(searchResult, statsResult) {
  const priceList = searchResult.data || []
  const total = searchResult.total || 0

  // 格式化数据
  const formattedList = priceList.map(item => ({
    ...item,
    price_date_str: formatDate(item.price_date)
  }))

  // 判断是否还有更多数据
  const hasMore = formattedList.length >= this.data.pageSize &&
                  this.data.priceList.length + formattedList.length < total

  // 累加数据
  const newList = this.data.currentPage === 1
    ? formattedList
    : [...this.data.priceList, ...formattedList]

  this.setData({
    priceList: newList,
    total,
    hasMore,
    loadingMore: false
  })
}

5. UI 状态 (index.wxml:129-145)

<!-- 加载更多状态 -->
<view class="load-more" wx:if="{{priceList.length > 0}}">
  <!-- 加载中 -->
  <view class="loading-more" wx:if="{{loadingMore}}">
    <t-loading theme="circular" size="40rpx" text="加载中..."></t-loading>
  </view>

  <!-- 没有更多数据 -->
  <view class="no-more" wx:elif="{{!hasMore}}">
    <text>已加载全部数据</text>
  </view>

  <!-- 继续滚动提示 -->
  <view class="scroll-hint" wx:else>
    <text>继续滚动加载更多</text>
  </view>
</view>

6. 样式动画 (index.wxss:223-260)

.load-more {
  padding: 32rpx 0;
  text-align: center;
  border-top: 1rpx solid #f0f0f0;
}

.scroll-hint {
  color: #0052D9;
  font-size: 26rpx;
  animation: pulse 2s ease-in-out infinite;  /* 呼吸灯效果 */
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}

7. 页面配置 (index.json:1-5)

{
  "onReachBottomDistance": 50  // 距离底部50px时触发
}

📊 使用示例

场景 1查询到 4000 条数据

用户操作:选择"昆明"地区 → 点击"查询价格"

系统行为:
1. 加载第1页20条→ 显示"共找到 4000 条结果,已加载 20 条"
2. 用户滚动到底部 → 自动加载第2页20条
3. 显示"共找到 4000 条结果,已加载 40 条"
4. 重复直到加载完全部 4000 条数据
5. 显示"已加载全部数据"

场景 2数据不足 20 条

用户操作:选择"大理"地区 → 点击"查询价格"

系统行为:
1. 加载第1页15条→ 显示"共找到 15 条结果,已加载 15 条"
2. 直接显示"已加载全部数据"(不会触发加载更多)

🎨 UI 效果

加载状态展示

┌─────────────────────────────┐
│ 共找到 4000 条结果,已加载 60条 │
├─────────────────────────────┤
│ 价格数据卡片 1               │
│ 价格数据卡片 2               │
│ 价格数据卡片 3               │
│ ...                         │
├─────────────────────────────┤
│  继续滚动加载更多            │  ← 蓝色闪烁提示
└─────────────────────────────┘

加载中状态

┌─────────────────────────────┐
│ 共找到 4000 条结果,已加载 80条 │
├─────────────────────────────┤
│ 价格数据卡片 ...             │
├─────────────────────────────┤
│  🔄 加载中...               │  ← 加载动画
└─────────────────────────────┘

已加载全部

┌─────────────────────────────┐
│ 共找到 4000 条结果,已加载 4000条│
├─────────────────────────────┤
│ 价格数据卡片 ...             │
├─────────────────────────────┤
│  已加载全部数据              │  ← 灰色提示
└─────────────────────────────┘

🚀 性能优化

1. 首屏加载优化

  • 从 100 条减少到 20 条(首屏速度提升 5 倍
  • 用户感知响应更快

2. 按需加载

  • 只加载用户需要查看的数据
  • 节省流量和内存

3. 防抖处理

  • 避免重复请求同一页数据
  • 减少服务器压力

4. 累加策略

  • 数据追加而非替换(避免列表闪烁)
  • 保持滚动位置

🔍 调试技巧

查看加载日志

// 在控制台查看分页信息
console.log('当前页:', this.data.currentPage)
console.log('已加载:', this.data.priceList.length)
console.log('总数:', this.data.total)
console.log('还有更多:', this.data.hasMore)

模拟触底加载

在微信开发者工具中:

  1. 点击"调试器" → "Console"
  2. 滚动页面到底部
  3. 查看"触底加载更多..."日志
  4. 观察网络请求 /api/prices/search?page=2

测试边界场景

// 场景 1数据量正好是 pageSize 的倍数
total = 40, pageSize = 20  应加载2页

// 场景 2数据量不足一页
total = 15, pageSize = 20  应加载1页显示"已加载全部"

// 场景 3数据量非常大
total = 10000, pageSize = 20  应加载500页

📝 代码变更清单

已修改文件

  1. pages/index/index.js

    • 新增 currentPage, pageSize, hasMore, loadingMore 状态
    • 重构 onSearch() 支持分页
    • 新增 onReachBottom() 触底加载
    • 新增 processSearchResult() 统一数据处理
  2. pages/index/index.wxml

    • 新增"加载更多状态"UI3种状态
    • 优化列表头部文案(显示已加载数量)
  3. pages/index/index.wxss

    • 新增 .load-more 样式
    • 新增 .scroll-hint 呼吸灯动画
  4. pages/index/index.json

    • 新增 onReachBottomDistance: 50 配置

🎯 后续优化建议

1. 虚拟列表(适用于超大数据量)

如果数据量超过 10000 条,建议使用虚拟列表:

// 只渲染可见区域的数据
// 微信小程序可使用 recycle-view 组件

2. 数据缓存

// 缓存已加载的数据,避免重复请求
const cacheKey = `prices_${region}_${material}_${page}`

3. 预加载(更激进的策略)

// 在滚动到 80% 时预加载下一页
// 用户感觉不到加载延迟

4. 加载更多按钮(可选)

为不喜欢滚动的用户提供备选方案:

<t-button wx:if="{{hasMore}}" bindtap="onLoadMore">
  加载更多
</t-button>

常见问题

Q1: 为什么不一次性加载所有数据?

A:

  • 性能问题4000 条数据会占用大量内存,导致页面卡顿
  • 网络问题:一次性加载会消耗大量流量,等待时间长
  • 用户体验:首屏加载慢,用户感知差

分页加载:按需加载,快速响应,流畅体验

Q2: 如何调整每页加载的数量?

A: 修改 index.js:70

pageSize: 20,  // 改为你想要的数量,建议 10-50

Q3: 触底加载不生效怎么办?

检查清单:

  1. 确认 onReachBottomDistance 已配置
  2. 确认 hasMore: true(还有数据)
  3. 确认 searched: true(已执行查询)
  4. 确认没有其他元素遮挡底部(如 TabBar

Q4: 如何禁用自动加载,改用手动点击?

A: 删除 onReachBottom() 方法,改用按钮:

<t-button wx:if="{{hasMore}}" bindtap="onLoadMore">
  加载更多
</t-button>

📚 相关文档


实现日期2026-01-07 版本v1.0 状态 已完成并测试