| name | implement-pagination |
| description | 做列表分页 / 加翻页 / 加载更多 / 历史消息翻页时触发。引导:判断 cursor vs offset → IM 场景必用 cursor → 选 before(向上加载更早)vs after(拉新消息)→ 用 hasMore 判断(不是 length < limit)→ 串行不并发。重点提示消息 ID = UnixMilli 时间戳的特殊性 + 多种"产品想用 offset 翻页"的反模式拦截。 |
| allowed-tools | ["Read","Edit"] |
列表分页实现
触发场景
- 做列表分页 / 加翻页 / 加载更多 / 滚动加载
- 历史消息翻页(特殊:消息 ID = 时间戳)
- 会话列表 / 商品列表 / 订单列表分页
- "改成第 1/2/3 页那种翻页器"(反模式,需拦截)
- "下拉刷新加载新消息"
步骤 1:判断分页模式
| 模式 | 适用 | 不适用 |
|---|
| cursor 分页(IM 默认) | 实时数据流(消息 / 会话 / 订单 / 通知) | 静态目录列表 |
| offset 分页(第 1/2/3 页) | 静态目录列表(settings / docs) | 任何 IM 场景(实时数据 offset 会错乱) |
IM 场景一律用 cursor 分页。如果产品要"翻页器" → 直接拒绝:实时追加消息会让 offset 错乱(同一个 offset 点指向的消息会变化),导致重复加载或漏加载。
步骤 2:Read 字典拿参数语义
Read .ai/knowledge/pagination.md 拿:
before / after / limit 参数完整语义
- 消息 ID = UnixMilli 时间戳的排序规则
- 标准翻页模式代码模板
步骤 3:选 before vs after
| 想加载 | 用 | 例子 |
|---|
| 更早的消息(向上滚动) | before: <最早消息 ID> | 历史消息翻页 |
| 更新的消息(下拉刷新) | after: <最新消息 ID> | 拉新消息 |
| 首屏 | 都不传,只传 limit | 初次加载 |
步骤 4:实现标准翻页(消息列表)
const result = imCore.feedMessages({
chatId: 'chat_123',
data: await api.getMessages({ chatId: 'chat_123', limit: 20 }),
});
if (result.hasMore) {
const oldestId = messages[0].id;
const moreResult = imCore.feedMessages({
chatId: 'chat_123',
data: await api.getMessages({ chatId: 'chat_123', before: oldestId, limit: 20 }),
});
}
const newestId = messages[messages.length - 1].id;
const newResult = imCore.feedMessages({
chatId: 'chat_123',
data: await api.getMessages({ chatId: 'chat_123', after: newestId, limit: 20 }),
});
会话列表类似,调 imCore.feedConversations 而非 feedMessages。
步骤 5:边界处理(必查)
| 边界 | 正确做法 |
|---|
| 是否还有更多 | 看 hasMore 字段,不是 msgs.length < limit(长度判断会漏数据) |
| 空列表 | msgs: [] + hasMore: false = 没数据,不是错误,不要 throw |
| cursor 存储 | ImCore 内部管理,前端不要自行存 |
| 并发翻页 | 同一个 chatId 必须串行,等上一个完成再发;并发会让 cursor 乱 |
| 排序 | Number(id) 降序(最新在前);不要用 createdAtTimestamp(可能与 ID 不一致) |
步骤 6:消息列表的特殊性
- 消息 ID = 字符串形式的毫秒时间戳(如
"1704067200000")
- 排序:
Number(id) 降序,新消息在数组头
- 加载更多时取
messages[0].id 作为 before(最早的消息)
- 拉新时取
messages[messages.length - 1].id 作为 after(最新的消息)
反模式(接产品需求时主动拦截)
| 产品要求 | 真实代价 |
|---|
| "改成翻页器(第 1/2/3 页)" | 禁止——IM 场景反模式,实时追加消息会让 offset 错乱 |
| "按时间排序而不是 ID" | 禁止——用 Number(id),时间戳可能与 ID 不一致 |
| "并发翻页让加载更快" | 禁止——cursor 会乱,必须串行 |
| "msgs 长度小于 limit 就是没数据" | 错——必须看 hasMore 字段,长度判断会漏数据 |
| "首屏加载多一些消息" | 改 limit(默认 20,最大 50),首屏体积变大;超过 50 后端截断 |
| "下拉刷新加载新消息" | 用 after 参数(不是 before) |