分页参数丢失的根本原因是未在paginate()中显式配置query参数以透传非page的get参数,正确做法是用array_diff_key过滤后传入request()->param(),而非依赖自动携带或模板层appends()。

分页链接里参数丢了,不是框架 bug,是你没告诉它要带哪些参数过去。
paginate() 的 query 配置必须显式传参
ThinkPHP 不会自动把当前 URL 的所有 GET 参数都塞进分页链接里。比如你访问 ?keyword=php&type=blog&page=2,点“下一页”后变成 ?page=3,keyword 和 type 全没了——这就是漏了 query 配置。
-
query是个数组,键是参数名,值是对应值,比如['keyword' => $keyword, 'type' => $type] - 最省事写法是直接用
request()->param(),但它会把page也包进去,而paginate()自己会处理page,重复会导致翻页错乱 - 推荐过滤掉分页相关参数:
array_diff_key(request()->param(), ['page' => '', 'p' => '']) - 如果你用的是 API 场景(如 POST JSON),
query就得手动拼,不能依赖request()->param()
appends() 是模板层补救手段,不是首选
$list->appends(['keyword' => $keyword]) 确实能在模板里临时加参数,但它只影响当前 render() 调用,且容易和控制器里的 query 配置冲突。一旦你在控制器里已经配了 query,再在模板里用 appends(),参数会被叠加两次。
- 只在简单场景(比如单个固定参数)且控制器没配
query时才考虑用appends() - 不要在循环里反复调用
appends(),它每次返回新对象,性能浪费 - 如果用了
simple()模式,appends()依然有效,但要注意它不改变原始分页对象的 URL 基础
var_page 改变页码参数名时,query 里别硬编码 page
你想把 ?page=2 改成 ?p=2,得在配置里设 'var_page' => 'p'。但很多人接着在 query 里还写 ['page' => input('page/d', 1)],结果 p=2 时 input('page') 拿不到值,参数就空了。
- 统一用
input($config['var_page'] ?? 'page')取当前页码 -
query数组里该用哪个 key,取决于你实际想透传的参数名,和var_page无关;var_page只影响页码本身的参数名 - 如果你设了
'var_page' => 'p',又希望保留旧链接兼容,可以同时支持两个参数:input('p/d', input('page/d', 1))
分页后修改数据对象会破坏 render() 上下文
有人为了方便,在控制器里写了 $list = $list->toArray() 或 json($list) 再传给模板,结果 {$list->render()} 报错或输出空字符串——因为 render() 必须作用于原始的 Paginator 对象,转成数组就只剩数据,没有分页元信息了。
- assign 给模板的变量必须是未转换的
Paginator实例 - 如果真要加工数据(比如加字段),用
$list->each(function ($item) { ... }),别动对象本身 - 调试时可以用
get_class($list)确认是不是think\Paginator或其子类
最容易被忽略的是:query 配置不是“可选”,而是“必填项”——只要你的分页页面带任何筛选条件,它就必须存在,否则用户一翻页,就回到无条件状态。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











