ThinkJS 2.x 分页组件 think-pagination 使用指南:从 countSelect 到模板渲染的完整实践
后端Web框架【免费下载链接】thinkjsUse full ES2015 features to develop Node.js applications, Support TypeScript.项目地址https://gitcode.com/gh_mirrors/thi/thinkjs点击查看免费下载本指南以 packages/think-pagination/README_v2.md 为骨架系统讲解 ThinkJS 2.x 场景下 think-pagination 的安装、控制器调用、模板渲染方式并结合仓库源码深入剖析其 URL 自动生成、页码窗口算法与 HTML 输出原理。读完本文你将能够在 ThinkJS 2.x 项目中用一行函数生成完整的分页 HTML并理解分页数据pagerData在模型层的来源与字段结构。一、think-pagination 是什么think-pagination 是 ThinkJS 生态中的分页渲染组件它接收模型层countSelect返回的分页数据结合当前请求上下文http对象与自定义选项输出一段完整的ul分页条 HTML。该组件面向 ThinkJS 2.x 设计对应文档为 README_v2.md若你使用 ThinkJS 3.x则应参考 packages/think-pagination/README.md两代版本的 API 结构基本一致主要差异是第二参数由http对象演变为ctx对象。组件本身是一个纯函数模块主入口为 packages/think-pagination/index.js依赖think-helper提供的escapeHtml工具做参数转义见 packages/think-pagination/package.json。二、安装在项目根目录执行npm install think-pagination1.6.0安装完成后即可在控制器中通过import引入import pagination from think-pagination;三、控制器中使用一行生成分页 HTML官方文档给出的控制器示例完整如下对应 README_v2 的 controller 小节import pagination from think-pagination; export default class think.controller.base { async indexAction(){ let data await this.model(user).page(this.get(page)).countSelect(); let html pagination(data, this.http, {}); this.assign(pagination, html); } }关键链路可以拆解为三步this.get(page)从 GET 请求中读取当前页码this.model(user).page(page).countSelect()返回分页数据集datapagination(data, this.http, {})生成 HTML 字符串this.assign(pagination, html)将其注入模板变量。3.1 pagerData 从哪来page() 与 countSelect() 的源码印证pagerData并非普通查询结果而是模型层countSelect返回的专用分页结构。在 packages/think-model/src/model.js 中page方法负责设置分页的偏移量page(page, listRows this.config.pagesize) { if (helper.isArray(page)) { listRows page[1] || listRows; page page[0]; } page Math.max(parseInt(page) || 1, 1); listRows Math.max(parseInt(listRows) || 10, 1); this.options.limit [listRows * (page - 1), listRows]; return this; }几个值得注意的细节第二个参数listRows默认取this.config.pagesize即每页条数可在模型配置中控制支持page([2, 5])数组写法此时page为 2、listRows为 5页码与每页条数都经过Math.max(..., 1)兜底非法值如 0、负数、NaN会被修正为最小值 1 或 10。countSelect的实现位于 packages/think-model/src/model.js其返回结构是 think-pagination 的数据契约const result Object.assign({ count: count, totalPages: totalPage }, data); // data { pageSize: pagesize, currentPage: currentPage } result.data count ? await this.select(options) : []; return result;最终pagerData包含以下字段字段含义来源count满足条件的总记录数count()聚合查询totalPages总页数Math.ceil(count / pageSize)think-model/src/model.jscurrentPage当前页码parseInt(limit[0] / limit[1] 1)think-model/src/model.jspageSize每页条数即limit[1]think-model/src/model.jsdata当前页的数据列表有数据时执行select(options)无数据时为空数组think-pagination 的 HTML 生成正是消费totalPages、currentPage、count这三个字段因此传入的pagerData必须来自countSelect或与之结构一致的对象。四、模板中渲染两种模板引擎的差异由于pagination()返回的是 HTML 字符串不同模板引擎的注入方式不同4.1 ejs{%-pagination%}4.2 nunjucks{{pagination | safe}}注意 nunjucks 默认会对变量做 HTML 转义分页字符串中包含ul、a等标签必须通过safe过滤器原样输出否则会被转义为纯文本导致样式失效而 ejs 中{%- ... %}语法本身即按原始 HTML 输出。五、API 详解pagination(pagerData, http, options)函数签名与 README_v2 的 api 小节一致pagination(pagerData, http, options)参数说明pagerDatamodel.countSelect()返回的分页数据http当前请求的 http 对象ThinkJS 2.x用于自动生成分页 URLoptions分页渲染选项5.1 options 完整配置{ desc: false, //show description pageNum: 2, url: , //page url, when not set, it will auto generated class: , //pagenation extra class text: { next: Next, prev: Prev, total: count: ${count} , pages: ${pages} } }对照 packages/think-pagination/index.js 中的Object.assign默认值逐项说明如下配置项默认值作用descfalse是否在分页条首部显示总记录数与总页数描述pageNum2当前页前后各展示的页码个数页码窗口半宽url分页链接模板为空时基于当前查询参数自动生成class附加到ul classpagination ...上的额外 CSS 类名text.nextNext“下一页”链接文案text.prevPrev“上一页”链接文案text.totalcount: __COUNT__ , pages: __PAGE__描述模板__COUNT__与__PAGE__为占位符注意 README_v2 中text.total写为${count}/${pages}的模板字符串风格而实际源码index.js是用replace(__COUNT__, ...)、replace(__PAGE__, ...)替换占位符因此__COUNT__、__PAGE__才是真正生效的写法本指南以源码为准。自定义示例let html pagination(data, this.http, { desc: true, pageNum: 3, class: my-pagination, url: /user/list?page__PAGE__, text: { next: 下一页, prev: 上一页, total: 共 __COUNT__ 条共 __PAGE__ 页 } });5.2 desc 描述条的生成逻辑当desc: true时源码会先输出一个禁用态列表项index.jsconst total options.text.total .replace(__COUNT__, pagerData.count) .replace(__PAGE__, pagerData.totalPages); html li classdisabledspan${total}/span/li;即把pagerData.count总记录数与pagerData.totalPages总页数代入描述模板渲染为li classdisabledspan.../span/li。六、源码级原理剖析6.1 单页直接返回空函数入口处有一道守卫index.jsif (pagerData.totalPages 1) return ;总页数不大于 1 时无需分页直接返回空字符串避免无意义的分页条占用页面空间。仓库测试 packages/think-pagination/test/index.js 正是针对该行为it (totalPages 1, function() { var html pagenation({totalPages: 1}); assert.equal(html, ); });6.2 URL 自动生成保留当前查询参数未显式指定options.url时getPageUrl会基于httpctx上的查询参数自动拼装分页链接index.jsconst getPageUrl (options, ctx) { let pageUrl options.url; if (!pageUrl) { let prefix (options.prefix || ) ?; const querys []; for (const name in ctx.query) { if (name page) { continue; } querys.push(helper.escapeHtml(name) helper.escapeHtml(ctx.query[name])); } prefix querys.join(); if (querys.length) { prefix ; } pageUrl prefix page__PAGE__; } return pageUrl; };其行为要点自动跳过page参数避免生成page2page3这类重复参数保留其余全部查询参数如搜索关键字、排序条件保证翻页不丢失当前筛选状态参数名与参数值均经helper.escapeHtml转义从源头防范 XSS支持options.prefix为链接附加自定义前缀生成的模板形如?keywordxxxpage__PAGE____PAGE__是页码占位符。6.3 页码窗口算法pageNum 决定显示多少个页码getPageIndexindex.js计算当前页前后各pageNum个页码const getPageIndex (pagerData, options) { const num options.pageNum || 2; const page pagerData.currentPage | 0 || 1; const totalPages pagerData.totalPages; const pageIndex []; let start page - num; let stop page num; if (start 1) { start 1; stop start num * 2 1; } if (stop totalPages) { stop totalPages; start totalPages - num * 2 - 1; } for (let i start; i stop; i) { if (i 1 i totalPages) { pageIndex.push(i); } } return pageIndex; };以默认pageNum: 2为例当前页在第 3~倒数第 3 页之间时窗口为[currentPage-2, currentPage2]即最多显示 5 个页码靠近首页时窗口起点修正为 1并扩展窗口保证始终有num*21个页码靠近末页时窗口终点修正为totalPages并同步前移起点数组内每个元素都经过i 1 i totalPages过滤保证不越界。6.4 HTML 输出结构Bootstrap 风格分页条最终输出为 Bootstrap 风格的分页条index.js完整结构如下ul classpagination !-- desc: true 时 -- li classdisabledspan共 100 条共 10 页/span/li !-- 当前页 1 时 -- li classpreva href?page2Prev/a/li !-- 窗口前有剩余页时 -- lia href?page11/a/li li classdisabledspan.../span/li !-- 页码窗口 -- lia href?page44/a/li li classactivea href?page55/a/li lia href?page66/a/li !-- 窗口后有剩余页时 -- li classdisabledspan.../span/li lia href?page1010/a/li !-- 当前页 总页数时 -- li classnexta href?page6Next/a/li /ul各列表项语义列表项出现条件说明li.disabled spandesc: true总记录数 / 总页数描述li.prev acurrentPage 1上一页链接指向currentPage - 1li a首页窗口起始页 1指向第 1 页li.disabled span ...窗口起始页 2省略号占位li.active a当前页高亮当前页码li.disabled span ...窗口末页 总页数 - 1尾部省略号占位li a末页窗口末页 总页数指向最后一页li.next acurrentPage totalPages下一页链接指向currentPage 1class选项传入时ul变为ul classpagination ${options.class}便于叠加自定义样式如居中、尺寸、主题色。七、边界行为与最佳实践7.1 越界页码的兜底countSelect在pageFlag为布尔值时会对越界页码做兜底think-model/src/model.js当前页超过总页数时true修正为第 1 页、false修正为最后一页从而保证currentPage始终落在合法区间内分页条不会出现“当前页不存在”的异常状态。7.2 每页条数的默认值countSelect中options.limit options.limit || [0, this.config.pagesize || 10]think-model/src/model.js即每页默认 10 条若在模型配置中设置pagesize则分页、page()与countSelect会统一采用该值。7.3 模板安全输出nunjucks 中务必使用{{pagination | safe}}若希望限制分页条长度可调小pageNum如1表示当前页前后各 1 个页码若项目使用固定路由风格 URL推荐显式指定url模板如/user/list?page__PAGE__避免依赖自动生成。7.4 版本适用性说明ThinkJS 2.x阅读 README_v2.md安装think-pagination1.6.0第二参数传this.http控制器继承think.controller.baseThinkJS 3.x阅读 README.md第二参数传this.ctx其余 options 配置保持一致。八、总结think-pagination 以极小的 API 面一个函数、七个配置项完成了“数据驱动 自动 URL Bootstrap 风格 HTML”的完整分页闭环数据侧由model.page().countSelect()提供count、totalPages、currentPage等字段渲染侧由getPageUrl保留查询参数自动生成链接、getPageIndex控制页码窗口、入口守卫处理单页场景。结合 index.js 源码与 test/index.js 测试你可以放心地将它接入 ThinkJS 2.x 项目并在需要时通过options自由定制描述文案、页码窗口、URL 模板与附加样式。赞分享后端Web框架【免费下载链接】thinkjsUse full ES2015 features to develop Node.js applications, Support TypeScript.项目地址https://gitcode.com/gh_mirrors/thi/thinkjs点击查看免费下载相关推荐think-pagination 分页组件实战指南从 countSelect 到视图渲染的完整链路think pagination 分页组件实战指南从 countSelect 到视图渲染的完整链路 本篇技术指南以 ThinkJS 3 生态中的分页组件 th后端Web框架think-logger3ThinkJS 3.x 基于 log4js 的日志模块完整使用指南think logger3ThinkJS 3.x 基于 log4js 的日志模块完整使用指南 think logger3 是 ThinkJS 3.x 官方配套后端Web框架Yii 2 数据分页完整指南Pagination 对象与 LinkPager 组件的实战用法Yii 2 数据分页完整指南Pagination 对象与 LinkPager 组件的实战用法 当单页需要展示的数据量过大时常见的做法是将数据拆分到多个页面后端Web框架上一篇HS2-HF Patch实战指南从零开始打造你的专属游戏体验下一篇20K Vocab Builder 提示词拆解与复刻自适应词汇学习工作流的完整设计逻辑创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

从App开发到Unity游戏开发:认知转型与AI辅助学习路径

从App开发到Unity游戏开发:认知转型与AI辅助学习路径

1. 从界面思维到空间思维:一次被迫的认知重启做了五年移动端应用开发,我一度以为自己对“软件”这件事已经摸得差不多了。页面、路由、状态管理、网络请求、数据持久化,这套东西闭着眼都能搭出来。直到去年接手一个轻量级3D互动项目&#xff…

2026/10/15 20:50:49 阅读更多 →
C语言printf多参数自增自减为何结果不确定?求值次序与序列点解析

C语言printf多参数自增自减为何结果不确定?求值次序与序列点解析

1. 从一个让人抓狂的输出结果说起如果你写过一段时间的C语言,大概率遇到过下面这种让人怀疑编译器是不是坏了的场景:明明变量在脑子里推演得好好的,结果printf一跑出来,数字跟预期完全对不上。尤其是当表达式里同时出现自增和自减…

2026/10/15 20:50:49 阅读更多 →
汇编语言上机四阶段:从.asm源文件到GDB调试的完整流程

汇编语言上机四阶段:从.asm源文件到GDB调试的完整流程

汇编语言与计算机系统结构这门课,真正让人卡住的往往不是指令语法,而是第一次上机时对完整流程没有概念。我见过不少同学,在编辑器里写好了汇编源文件,却不知道接下来该敲什么命令,也不知道每个命令到底做了什么。这篇…

2026/10/15 20:50:49 阅读更多 →

最新新闻

2026前端AI编程工具实测:从Figma2Code到Agent闭环,TaoToken统一Key怎么配

2026前端AI编程工具实测:从Figma2Code到Agent闭环,TaoToken统一Key怎么配

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 21:39:55 阅读更多 →
给 Coding Agent 装上 LSP:别再让它靠 grep 猜代码,TaoToken 统一 Key 打通工具链

给 Coding Agent 装上 LSP:别再让它靠 grep 猜代码,TaoToken 统一 Key 打通工具链

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 21:39:55 阅读更多 →
蓝桥杯CT107D实战:DS18B20单总线驱动与避坑指南

蓝桥杯CT107D实战:DS18B20单总线驱动与避坑指南

1. 为什么CT107D上的DS18B20值得单独拿出来讲蓝桥杯单片机组的板子——CT107D,几乎是每个参赛选手绕不开的硬件平台。这块板子上集成了不少外设,数码管、独立按键、矩阵键盘、蜂鸣器、继电器、DS1302、AT24C02、DS18B20、超声波、红外接收等等&#xff0…

2026/10/15 21:39:55 阅读更多 →
Java爬虫实战:用Jsoup高效解析网页表格并导出CSV

Java爬虫实战:用Jsoup高效解析网页表格并导出CSV

简介:这是一个基于Java与Jsoup库抓取网页表格数据的入门实例,适用于在MyEclipse环境中学习网络爬虫原理的开发者,目标是掌握从HTML页面提取结构化表格信息的完整方法。资源包为zip格式,共24个文件,其中包含7个Java源码…

2026/10/15 21:39:55 阅读更多 →
树莓派4 UART多串口配置与通信实战指南

树莓派4 UART多串口配置与通信实战指南

1. 为什么树莓派 4 的 UART 值得单独拿出来聊 树莓派 4 这块板子,但凡你玩过一阵子,大概率都会碰到一个绕不开的需求:接一个串口设备。可能是 GPS 模块、可能是某款工业传感器、可能是和另一块单片机做点对点通信,也可能是调试一个…

2026/10/15 21:39:55 阅读更多 →
大模型指令微调实战:从LoRA选型到数据配比与避坑指南

大模型指令微调实战:从LoRA选型到数据配比与避坑指南

简介:这份PPT面向自然语言处理与大模型方向的学习者与开发者,系统梳理大模型指令微调(Instruction Tuning)的核心概念与整体脉络。内容从NLP四范式切入,依次讲解传统机器学习、深度学习、预训练加微调以及预训练加Prom…

2026/10/15 21:38:54 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →