后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载分页Pagination是 Web 应用中最常见的需求之一当数据量远超单页展示能力时将数据拆分到多页、每页只加载一小部分既保证了页面响应速度也降低了数据库压力。本篇技术指南以 Yii 2 框架的分页方案为核心完整讲解[[yii\data\Pagination]]对象的三大核心属性、与数据库查询的配合方式、LinkPager分页组件以及手动构建分页链接的方法并结合框架源码与测试用例说明其底层原理。读完本文你将能在控制器与视图中独立实现一套完整、可定制、与 Yii 2 深度集成的前后端分页方案。一、为什么需要分页Yii 2 的分页抽象当数据量大到无法在单页中合理展示时业界通用做法是将其拆分为多个页面每个页面只展示一部分数据这就是分页。Yii 2 使用yii\data\Pagination对象来集中表达一套分页方案的全部信息总共有多少条数据、每页展示多少条、当前处于第几页。它位于 framework/data/Pagination.php实现Linkable接口既能被视图组件消费也能直接输出导航链接。这个对象的设计目标是一次创建、多处复用同一个Pagination实例既可以传给数据库查询计算OFFSET/LIMIT也可以传给分页组件渲染按钮还可以用来生成任意页面的 URL避免了在控制器、视图、模型层各自维护页码状态。二、Pagination 对象的三大核心属性Pagination对象用三个属性完整描述一个分页方案这也是官方文档重点强调的三个概念属性说明默认值totalCount数据条目总数通常远大于单页展示的条目数0pageSize每页包含的数据条目数20page当前页码基于 0即 0 表示第一页0在源码中这三者分别对应 Pagination.php 的public $totalCount 0;、L134 的public $defaultPageSize 20;以及 getPage() 中从请求参数解析当前页码的逻辑。需要特别强调的是page是从 0 开始计数的page 0是第一页page 1是第二页。这与 URL 中用户看到的页码从 1 开始存在差异Yii 会在生成 URL 时自动完成1转换详见第五节。三、实战在控制器中结合数据库查询实现分页3.1 核心代码count offset limit 三步走将Pagination用于数据库查询是官方文档给出的标准用法核心思路是先数总数再切分页。以下代码完整继承自官方指南参见 docs/guide/output-pagination.mduse yii\data\Pagination; // 创建一个 DB 查询来获得所有 status 为 1 的文章 $query Article::find()-where([status 1]); // 得到文章的总数注意此时尚未真正从数据库拉取文章数据 $count $query-count(); // 使用总数来创建分页对象 $pagination new Pagination([totalCount $count]); // 使用分页对象计算出的 offset/limit 来填充查询并取得当前页数据 $articles $query-offset($pagination-offset) -limit($pagination-limit) -all();这段代码的执行流程非常清晰构造查询Article::find()-where([status 1])只构建查询条件不立即执行统计总数$query-count()生成SELECT COUNT(*)语句取得总条数作为totalCount创建分页对象new Pagination([totalCount $count])取当前页数据$pagination-offset和$pagination-limit会根据当前页码实时计算$query-offset(...)-limit(...)-all()最终执行SELECT * ... LIMIT offset, limit。$pagination-offset与$pagination-limit是只读属性其计算逻辑位于 getOffset() 与 getLimit()getOffset()返回当前页码 × 每页条数即$this-getPage() * $pageSizegetLimit()直接返回$pageSize当每页条数小于 1即无限分页时返回-1对应 SQL 中不限制返回行数的语义。3.2 完整的控制器动作示例上述逻辑在真实控制器中通常会与视图渲染结合。Pagination类自身的文档注释见 Pagination.php给出了一个完整范例public function actionIndex() { $query Article::find()-where([status 1]); $countQuery clone $query; $pages new Pagination([totalCount $countQuery-count()]); $models $query-offset($pages-offset) -limit($pages-limit) -all(); return $this-render(index, [ models $models, pages $pages, ]); }这里使用clone $query克隆查询对象用于计数避免count()对原查询对象造成状态污染是官方推荐的安全写法。随后将$models与$pages一并传入视图。3.3 当前页是如何确定的在 3.1 的例子中究竟返回哪一页的数据答案取决于请求中是否带有名为page的查询参数。默认情况下Pagination会尝试从page参数读取当前页码若参数缺失则回退为 0第一页。该逻辑体现在 getPage() 中public function getPage($recalculate false) { if ($this-_page null || $recalculate) { $page (int) $this-getQueryParam($this-pageParam, 1) - 1; $this-setPage($page, true); } return $this-_page; }注意两个细节请求参数中的page按从 1 开始解析内部减 1 后转为从 0 开始的页码解析出的页码会经过 setPage() 的范围校验当页码超出总页数时自动收敛到最后一页小于 0 时收敛为 0避免出现越界页或负页。四、用 LinkPager 组件渲染分页按钮数据取回后还需要让用户能够切换页面。Yii 2 提供了[[yii\widgets\LinkPager]]组件它接收一个Pagination对象自动渲染一栏可点击的页码按钮。官方文档给出的最小用法如下use yii\widgets\LinkPager; echo LinkPager::widget([ pagination $pagination, ]);LinkPager的实现位于 framework/widgets/LinkPager.php其核心渲染逻辑在 renderPageButtons() 中。结合源码可以了解到它的默认行为与常用可配置项属性默认值说明maxButtonCount10最多同时显示的页码按钮数量超出时自动收拢为窗口首/尾页附近展开nextPageLabelraquo;下一页按钮标签设为false可隐藏prevPageLabellaquo;上一页按钮标签设为false可隐藏firstPageLabelfalse首页按钮标签默认不显示lastPageLabelfalse末页按钮标签默认不显示hideOnSinglePagetrue只有一页时自动隐藏整个分页条options[class pagination]分页条外层容器默认ul的 HTML 属性activePageCssClassactive当前选中页按钮的 CSS 类disabledPageCssClassdisabled禁用状态按钮的 CSS 类registerLinkTagsfalse是否在页面head中注册prev/next/first/last的link rel标签从 renderPageButtons() 可以看到当pageCount 2且hideOnSinglePage为true时组件直接返回空字符串按钮窗口的计算则由 getPageRange() 完成它基于maxButtonCount以当前页为中心截取页码范围并在接近首尾时自动平移窗口。另外LinkPager的 init() 会强制校验pagination属性必须被设置否则抛出InvalidConfigException。五、手动构建分页 URLcreateUrl 详解某些场景下如自定义 UI、生成分享链接、REST 响应你需要自己创建指向特定页面的 URL。此时可使用[[yii\data\Pagination::createUrl()]]它接收一个页码参数并返回格式正确的 URL。官方文档示例// 指定要创建的 URL 应使用的路由不指定则使用当前请求的路由 $pagination-route article/index; // 显示: /index.php?rarticle%2Findexpage101 echo $pagination-createUrl(100); // 显示: /index.php?rarticle%2Findexpage102 echo $pagination-createUrl(101);注意createUrl()接收的是从 0 开始的内部页码但 URL 中输出的page参数是从 1 开始的用户页码——传入 100 会生成page101。这个1转换在 createUrl() 中完成if ($page 0 || $page 0 $this-forcePageParam) { $params[$this-pageParam] $page 1; } else { unset($params[$this-pageParam]); }结合 createUrl() 的完整实现其行为还有以下几点值得掌握路由来源route属性未设置时自动使用当前请求的路由Yii::$app-controller-getRoute()保留查询参数URL 会保留当前请求中的其他查询参数如搜索关键词qparams属性可显式指定参与 URL 构建的参数集params未设置时默认取$_GET强制页码参数forcePageParam默认为true即使当前是第一页也会输出page1设为false后第一页 URL 将不含page参数测试用例见 PaginationTest.php每页条数参数当pageSize与默认值不一致时URL 中会附带per-page参数对应pageSizeParam属性从而允许用户通过 URL 调整每页数量绝对 URL第三个参数$absolute true时返回绝对地址常用于 REST 场景。getLinks()方法Pagination.php会基于createUrl()一次性生成self、first、last、prev、next五个导航链接这正是LinkPager注册link标签及 REST 序列化器输出_links的数据来源。六、自定义页码参数名pageParam如果项目出于 SEO 或路由规范考虑不希望使用默认的page查询参数可以通过pageParam属性重命名。官方文档给出的提示如下Tip: 创建分页对象时可以通过配置[[yii\data\Pagination::pageParam|pageParam]]属性来自定义查询参数page的名字。$pagination new Pagination([ totalCount $count, pageParam p, // URL 中显示 ?p2 而非 ?page2 ]);该属性定义于 Pagination.phppublic $pageParam page;。与之配套的还有pageSizeParam默认per-page用于自定义每页条数参数名。修改后getPage()的解析、createUrl()的 URL 生成都会统一使用新的参数名全程无缝切换。七、分页与数据提供器、REST 的联动7.1 ActiveDataProvider 自动分页在实际项目中更常见的做法是使用ActiveDataProvider让框架自动完成分页。yii\data\ActiveDataProvider内部会创建并持有Pagination实例并在 prepareModels() 中自动将分页计算出的limit与offset应用到查询上同时把totalCount回填给分页对象。因此配置化地声明即可获得分页能力$provider new ActiveDataProvider([ query Article::find()-where([status 1]), pagination [ pageSize 20, ], ]);这种模式下无需手动编写count()与offset()/limit()LinkPager直接消费$provider-getPagination()即可。7.2 REST 响应中的分页头信息在 RESTful API 场景下yii\rest\Serializer会利用Pagination在响应中输出标准化的分页信息见 framework/rest/Serializer.phpHTTP 响应头X-Pagination-Total-Count总数、X-Pagination-Page-Count总页数、X-Pagination-Current-Page当前页从 1 开始、X-Pagination-Per-Page每页条数以及Link头中的first/last/prev/next链接见 addPaginationHeaders()响应体当设置了_links与_meta信封时序列化结果中会附带导航链接与totalCount、pageCount、currentPage、perPage元信息见 serializePagination()。这些输出全部复用同一个Pagination对象的getLinks()、getPageCount()、getPageSize()等方法充分体现了该对象一处计算、多方消费的设计价值。八、源码级验证Pagination 的边界行为框架测试套件 tests/framework/data/PaginationTest.php 对上述行为做了系统验证可作为理解边界语义的权威参考URL 生成testCreateUrlcreateUrl(2)生成page3证明内部页码到 URL 页码的1转换传入pageSize时 URL 附带per-page传入自定义params时保留额外查询参数页码校验testValidatePagetotalCount100、pageSize10时setPage(999, true)会被收敛为第 9 页最后一页总页数计算testPageCountpageCount ceil(totalCount / pageSize)如totalCount15、pageSize2时总页数为 8偏移与限制testGetOffset、testGetLimitpageSize2、page2时offset为 4pageSize小于 1 时limit返回-1表示不限制导航链接testGetLinksgetLinks()仅在第一页省略prev、在最后一页省略next且永远包含self/first/last当总页数大于 0 时。九、小结Yii 2 的分页体系以yii\data\Pagination对象为核心向上对接数据库查询offset/limit、分页组件LinkPager、数据提供器ActiveDataProvider与 REST 序列化器向下则通过createUrl()统一输出符合路由规范的页码 URL。掌握三个核心属性totalCount、pageSize、page、两套渲染方式LinkPager组件与手动createUrl以及pageParam/forcePageParam/pageSizeLimit等定制开关即可在 Web 与 REST 场景中构建健壮、可定制且与框架深度一致的分页能力。本文对应的官方指南英文版位于 docs/guide/output-pagination.md中文版位于 docs/guide-zh-CN/output-pagination.md核心实现可进一步研读 framework/data/Pagination.php 与 framework/widgets/LinkPager.php。赞分享后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载相关推荐Yii 2 数据分页实战指南Pagination 对象与 LinkPager 分页组件全解析Yii 2 数据分页实战指南Pagination 对象与 LinkPager 分页组件全解析 本文以 Yii 2 官方指南 Pagination https:后端Web框架Yii 2 数据分页完整指南Pagination 对象与 LinkPager 组件的实战用法Yii 2 数据分页完整指南Pagination 对象与 LinkPager 组件的实战用法 当单页需要展示的数据量过大时常见的做法是将数据拆分到多个页面后端Web框架Yii 2 分页Pagination完全指南从 DB 查询分页到 LinkPager 分页按钮Yii 2 分页Pagination完全指南从 DB 查询分页到 LinkPager 分页按钮 本指南围绕 Yii 2 框架的 yii\data\Pagi后端Web框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考