小程序-客户端列表页布局与分页.md 7.4 KB

小程序:列表页布局与分页(实践备忘)

本文档归纳 uni-app + Vue3 在「分页加载、滚动触底加载、列表与固定底栏」等场景下的可复用思路;客户端、供应商端、配送员端技术栈一致,均可套用(差异主要在接口与业务字段)。下文第 8 节为供应商/配送员端当前实现扫描与改造优先级。


1. 分页与滚动加载

1.1 状态拆分

状态 用途
loading 首屏或整表刷新(reset = true)
loadingMore 触底加载下一页(reset = false)
page / nextPage 当前或下一页页码
hasMore 是否还有下一页
total / totalPages(可选) 服务端分页元信息

原则:首屏与「加载更多」不要共用一个布尔值,避免触底时把整页打成骨架屏,或重复并发请求。

1.2 请求与列表更新

  • fetchList(reset: boolean)
    • reset === true:page = 1,清空 list,走首屏 loading。
    • reset === false:在 !loadingMore && hasMore guard 下请求 nextPage,结果 concat 到 list。
  • onShow:按业务决定是每次都 fetchList(true),还是仅首次进入刷新。
  • 删改、设默认等:若一致性要求高,可 fetchList(true) 整表刷新;若列表项有稳定 id 且接口支持,也可局部更新单条以省流量。

1.3 「是否还有更多」

  1. 优先用服务端:totalPages、total + pageSize 判断 currentPage < totalPages。
  2. 兜底:若老接口未返回 totalPages,可用「本页条数 === pageSize」近似推断可能还有下一页(最后一页不满 pageSize 时自然停止)。

2. 同一列表接口两种返回形态(兼容)

适用于「列表页要分页,其它页面仍要全量」的场景(如收货地址)。

约定示例:

  • 不带 page(或不传分页参数):响应为 数组 [],供选地址、下单、购物车等沿用旧逻辑。
  • 带 page(及 pageSize):响应为 对象
    { list, total, page, pageSize, totalPages }。

注意:各调用方只在自己需要的形态下传参;列表页专用分页结构,避免全局把 data 当成数组解析。


3. 页面布局:谁滚动、谁固定

3.1 目标

  • 列表区域独立滚动,支持 @scrolltolower 触底加载。
  • 底部「新增 / 结算」等主按钮 固定在视口底部,不因列表变长被顶出屏幕。
  • 尽量避免 整页纵向滚动 与 内部 scroll-view 同时滚动(手势冲突、高度异常)。

3.2 推荐结构(示意)

页面根(flex 列、占满可视高度)
├── 可选:顶部固定区(标题、筛选)
├── scroll-view(flex:1,列表-only)
│   └── 列表项 … + 底部「没有更多了」提示
└── 固定底栏(按钮区,在 scroll-view 外)

3.3 与 pages.json 的配合

若整页不应跟手滚动、仅内部区域滚动,可为该页配置 disableScroll: true(按 uni-app 文档与项目现状使用),减少双滚动问题。


4. scroll-view 与 Flex 的常见坑

  • scroll-view 同时 flex: 1 又写 height: 100%:在部分端上高度计算异常,表现为内容被裁切、触底不触发、scrolltolower 不稳定。
  • 更稳妥做法:外层列布局占满屏;中间列表容器使用 flex: 1; min-height: 0(必要时 flex-basis: 0),把剩余高度交给 scroll-view,由 flex 约束高度而不是与 height: 100% 打架。

5. H5 固定层与安全区

在 H5 或模拟器上,固定顶/底栏可能被 导航栏、tabBar 遮挡。

  • 顶:top: var(--window-top) 等(按 uni-app 环境变量文档使用)。
  • 底:bottom: var(--window-bottom, 0px) 或与 tabBar 高度策略一致。

若仍有个别机型异常,再评估该页 navigationStyle: custom 等方案。


6. 新列表页自检清单

  • 分页参数与响应结构是否与后端约定一致(数组 vs 对象)。
  • loading / loadingMore 分离,触底有防抖或 guard,避免重复请求。
  • hasMore 优先用 totalPages,有兜底逻辑。
  • 列表在 scroll-view 内,主按钮在 scroll-view 外固定。
  • 中间区域 flex + min-height: 0,避免 scroll-view 高度为 0 或 100% 冲突。
  • 需要时页面 disableScroll,仅内部滚动。
  • H5 固定层是否用 --window-top / --window-bottom 避让系统 UI。

7. 本项目相关参考(实现落点)

以下文件曾按上述思路调整,可作对照阅读(以仓库当前版本为准):

  • 首页、购物车:商品/购物车列表分页 + 左右/上下分栏滚动。
  • 订单列表:分页 + totalPages 与触底加载。
  • 收货地址列表:scroll-view + 底部固定「新增」+ 地址分页;其它页面对地址接口仍用全量数组形态。

8. 供应商端 / 配送员端:现状与建议优先级

以下基于仓库内 miniprogram/src/pages/supplier、miniprogram/src/pages/deliverer 的只读扫描(接口若后续扩展分页,前端按第 1~2 节模式对接即可)。

8.1 供应商端

优先级 页面路径 现状摘要 建议
P0 supplier/quotation/quotation.vue 仅请求 page=1&pageSize=50;列表每条再请求报价详情以计算已报/未报数量(N+1) ① 列表接口分页 + 触底加载;② 优先让列表接口直接带 quotedCount / unquotedCount(或等价字段),避免每条再打详情接口
P1 supplier/delivery/delivery.vue page=1&pageSize=50,有纵向 scroll-view,无加载更多 分页 + @scrolltolower;若将来底部有固定操作区,按第 3 节拆出固定底栏
P1 supplier/address/address.vue 取货地址全量 GET,普通 view 列表 + 底部按钮 与客户端地址一致:可选 双形态接口 + scroll-view + 固定「新增」+ 分页(地址多时避免底栏被顶没)
P2 supplier/price-list/price-list.vue 全量列表,无 scroll-view 数据量上来后加分页与可滚动列表壳
另注 supplier/inquiry/inquiry.vue 先拉「当前询价单」再拉详情 整单商品(非典型长列表分页) 文档中的「双栏各自滚动、Flex 高度」仍可借鉴;若单询价商品极大,再考虑后端商品维度分页 + 前端滚动加载

8.2 配送员端

优先级 页面路径 现状摘要 建议
P0 deliverer/snatch/snatch.vue page=1&pageSize=20,无第二页;scroll 使用 height: 100vh 确认后端 totalPages 后做触底加载;布局上注意第 4 节(100vh 与 flex / 安全区)
P1 deliverer/task/task.vue page=1&pageSize=50,有 scroll-view 与客户端订单列表同一套:分页元数据 + loadingMore + scrolltolower
P2 deliverer/home/home.vue 首页内嵌任务列表,同样 page=1&pageSize=50 首页可保持「摘要条数」或较小 pageSize;完整列表以 task 页为准即可

8.3 pages.json 提示

供应商、配送员列表页当前多数 未 设置 disableScroll: true。若在具体页出现整页与 scroll-view 双滚动,再按第 3.3 节为该页单独打开。


文档版本:客户端分页与布局实践;补充 2026 年供应商/配送员端扫描与优先级。