ThinkPHP 8分页接口必须手动用paginate()+items()/total()组装JSON,返回code/msg/count/data标准结构,data为纯索引数组;URL参数需与input('page')/input('limit')对齐,否则Layui报“data is not defined”或仅渲染第一页。

ThinkPHP 8 分页接口必须用 paginate() + items()/total() 手动组装 JSON
直接 return $list->render() 或 $list->toArray() 会失败——Layui 表格只认 code/msg/count/data 四个顶层键,且 data 必须是纯索引数组。常见错误是返回带分页元信息的对象(如 current_page、last_page),导致前端报 data is not defined 或只渲染第一页。
正确做法是拆开取值再组装:
-
$list->total()拿真实总条数,别用count($list)(它只返回当前页数据量) -
$list->items()提取纯数据数组,别用$list->all()(会把元信息塞进data) - 手动构造数组:
['code' => 0, 'msg' => '', 'count' => $list->total(), 'data' => $list->items()] - 最后
return json($data),确保字段名一个字母都不能错
URL 参数必须匹配 input('page') 和 input('limit')
Layui 表格默认发 ?page=1&limit=10,而 ThinkPHP 的 paginate() 默认读 page 和 size。参数不一致会导致分页失效,后端始终返回第一页数据。
两种解法,推荐后者:
立即学习“PHP免费学习笔记(深入)”;
- 前端改 URL:在 Layui
request配置里把page改成size,或用parseData重写请求参数 - 后端适配:控制器里显式取
$page = (int) $this->request->get('page', 1)和$limit = (int) $this->request->get('limit', 10),再传给paginate($limit, false, ['page' => $page])
JSON 响应结构被中间件/异常覆盖怎么办
即使你写了 return json($data),如果项目启用了统一响应中间件或全局异常处理,仍可能被二次包装成 {code:500, msg:"xxx", data:null},导致 Layui 解析失败。
检查点:
- 确认中间件是否对
\think\response\Json实例做了拦截——如果是,需在中间件handle()中加判断:if ($response instanceof \think\response\Json) { return $response; } - 验证失败(
ValidateException)默认返回结构是{code:0, validate:[]},和标准 API 不兼容,必须通过中间件兜底重写为{code:400, msg:"xxx", data:[]} - 别在控制器里混用
success()或error(),它们结构固定且不含count字段,无法满足 Layui 分页要求
前端解析失败时先查 Content-Type 和编码
即便 JSON 结构完全正确,Layui 仍可能报错或空白,大概率是响应头或编码问题。
关键检查项:
-
json()自动设置Content-Type: application/json; charset=utf-8,但若中间件或日志提前输出了内容(比如 Trace 开启时),会触发Cannot modify header information,导致头信息缺失 - 确保没手动调用
header()或echo json_encode(),绕过框架响应机制极易出错 - 中文乱码?确认
json()调用时加了JSON_UNESCAPED_UNICODE,否则前端看到的是\u4f60\u597d - 用浏览器 DevTools 的 Network 面板看响应体是否完整、是否有 BOM 头或前置空格
count 字段或 data 里混进对象属性,Layui 就直接放弃解析。



















