news 2026/9/17 2:18:41

radix-vue PaginationList 组件完全指南:分页项列表的渲染与控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
radix-vue PaginationList 组件完全指南:分页项列表的渲染与控制

radix-vue PaginationList 组件完全指南:分页项列表的渲染与控制

【免费下载链接】radix-vueAn open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue项目地址: https://gitcode.com/GitHub_Trending/ra/radix-vue

本篇技术指南聚焦 radix-vue(原 Radix Vue)组件库中的PaginationList组件,讲解它作为分页条"中间列表"的职责:如何通过作用域插槽获取由PaginationRoot计算好的页码与省略号项目集合,以及as/asChild属性如何控制渲染元素。结合源码实现,你将掌握分页列表的生成算法、与PaginationListItemPaginationEllipsis的协作方式,并能直接写出可运行、无障碍友好的完整分页组件。

组件定位:Pagination 家族中的"列表容器"

radix-vue 的分页能力由多个组件协作完成,源码位于 packages/core/src/Pagination:

  • PaginationRoot:管理当前页page、总页数pageCount等状态,并通过注入上下文向子组件提供数据;
  • PaginationList本文主角,一个纯展示型容器,不直接渲染任何页码按钮,而是通过items作用域插槽把计算好的"分页项目集合"交给使用者渲染;
  • PaginationListItem/PaginationEllipsis:分别渲染单个页码按钮和省略号;
  • PaginationFirst/PaginationPrev/PaginationNext/PaginationLast:首、上一、下一、末页跳转按钮。

在典型的组合中,PaginationList充当分页条的"中间地带"——左右两侧是跳转按钮,中间则是一个由items驱动的循环渲染区。相关源码可对照 PaginationList.vue 与 PaginationRoot.vue。

Props:继承自 Primitive 的两个核心属性

根据官方文档(PaginationList.md),PaginationList的 Props 完全继承自PrimitiveProps,只有两项:

NameDescriptionTypeRequiredDefault
as组件渲染为的元素或组件,可被asChild覆盖。AsTag \| ComponentNo"div"
asChild将默认渲染元素替换为传入的子元素,并合并两者的 props 与行为。详情见官方 Composition 指南。booleanNo-

从实现看,PaginationList.vue 的模板即是一个Primitive包裹:

<Primitive v-bind="props"> <slot :items="transformedRange" /> </Primitive>

由于PaginationListProps extends PrimitiveProps,它默认渲染为<div>。实际使用中通常无需修改,因为列表本身只负责提供插槽数据;若需要语义化标签(如ul),可通过as="ul"调整,或在更细粒度上由PaginationListItem各自控制渲染元素。Primitive的实现位于 packages/core/src/Primitive。

Slots:items—— 分页项目集合

文档中定义的本组件唯一插槽:

NameDescriptionType
items分页项目{ type: "ellipsis"; } \| { type: "page"; value: number; }

items是一个可辨识联合(discriminated union)数组,每个元素要么是页码项{ type: 'page'; value: number },要么是省略号项{ type: 'ellipsis' }。类型定义见 PaginationList.vue。

结合 story/_Pagination.vue 的官方用法,通过v-slot="{ items }"取出数据后,通常配合v-for循环渲染:

<PaginationList v-slot="{ items }" class="flex items-center gap-2"> <PaginationFirst /> <PaginationPrev /> <template v-for="(page, index) in items"> <PaginationListItem v-if="page.type === 'page'" :key="index" :value="page.value" class="border rounded px-4 py-2>const transformedRange = computed(() => { return transform( getRange( rootContext.page.value, rootContext.pageCount.value, rootContext.siblingCount.value, rootContext.showEdges.value, ), ) })

getRange:页码窗口计算

getRange(currentPage, pageCount, siblingCount, showEdges)返回(string | number)[],其中数字代表真实页码、字符串'ellipsis'代表省略号。其核心逻辑(参考自 chakra-ui/zag 的 pagination 工具函数):

  • showEdges = false(默认):采用"滑动窗口"策略。itemCount = siblingCount * 2 + 1;当总页数小于窗口大小时直接返回全部页码;当前页靠近开头时返回[1..itemCount];靠近末尾时返回末尾的itemCount个页码;位于中间时返回[currentPage - siblingCount .. currentPage + siblingCount]
  • showEdges = true:始终保留第 1 页、最后 1 页与最多两个省略号。此时totalPageNumbers = min(2 * siblingCount + 5, pageCount),再通过showLeftEllipsis/showRightEllipsis的组合判断,分别产生"左侧省略"、"右侧省略"、"双侧省略"或"全量"四种形态(源码中有详细注释说明2 * siblingCount + 5的构成:两侧兄弟页 ×2、左右省略号 ×2、首尾页 ×2 与当前页 ×1)。

transform:统一为插槽数据类型

transform(string | number)[]映射为插槽要求的联合类型——数字转{ type: 'page', value },字符串(即'ellipsis')转{ type: 'ellipsis' }

与 Root 参数的联动

PaginationRoot的默认值(见 PaginationRoot.vue)直接决定了列表形态:

  • siblingCount默认2:当前页两侧各显示 2 个页码;
  • showEdges默认false:不强制显示首尾页;
  • total默认0pageCount = Math.max(1, Math.ceil(total / (itemsPerPage || 1))),因此total=0时总页数为 1,所有跳转按钮呈禁用态。

PaginationListItem/PaginationEllipsis的分工

items只是"数据",真正把数据渲染成可交互元素的分别是:

  • PaginationListItem.vue:接收value属性,内部通过computed判断isSelected(当前页等于自身值),并自动输出无障碍属性——aria-label="Page {value}"、选中时aria-current="page"data-selected="true",点击时调用上下文中的onPageChange更新页码;在禁用状态下点击事件被拦截(!disabled && rootContext.onPageChange(value))。
  • PaginationEllipsis.vue:渲染data-type="ellipsis"的占位元素,默认内容为省略号字符&#8230;

测试用例 Pagination.test.ts 验证了这些行为:默认首屏第 1 页data-selected="true"、点击"下一页"后选中态切换到第 2 页、showEdges开启后第 1 页与第 10 页始终存在,且全部通过vitest-axe无障碍检查。

完整实战示例

将以上内容组合,一个完整的分页条(数据共 100 条、每页 10 条、共 10 页)如下:

<script setup lang="ts"> import { ref } from 'vue' import { PaginationEllipsis, PaginationFirst, PaginationLast, PaginationList, PaginationListItem, PaginationNext, PaginationPrev, PaginationRoot, } from 'radix-vue' const page = ref(1) </script> <template> <PaginationRoot v-model:page="page" :total="100" :items-per-page="10"> <PaginationList v-slot="{ items }" class="flex items-center gap-2"> <PaginationFirst /> <PaginationPrev /> <template v-for="(item, index) in items" :key="index"> <PaginationListItem v-if="item.type === 'page'" :value="item.value" class="border rounded px-4 py-2 contenteditable="false">【免费下载链接】radix-vueAn open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue项目地址: https://gitcode.com/GitHub_Trending/ra/radix-vue

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 2:18:32

AI率检测与降低全攻略:从原理到工具实测,一站式论文工作流

每年到了三四月&#xff0c;论文人集体变身“夜行动物”&#xff1a;白天在Word里赶初稿&#xff0c;晚上在绘图软件里画框架图&#xff0c;凌晨又要对着查重报告逐句删红字。好不容易把重复率压下去&#xff0c;学校系统一查&#xff0c;又弹出来一个叫“AI率”的东西。那一刻…

作者头像 李华
网站建设 2026/9/17 2:17:54

Git换行符警告真相:CRLF与LF跨平台协作指南

1. 这个警告不是Bug&#xff0c;是Git在帮你守住换行符的底线你在 IntelliJ IDEA 里点下 Commit 按钮&#xff0c;弹出那个红色警告框&#xff1a;“You are about to commit CRLF line separators to the Git repository…”——第一反应往往是慌&#xff1a;是不是代码坏了&a…

作者头像 李华
网站建设 2026/9/17 2:16:56

SpringBoot+Vue网上书城毕业设计:从解压到运行全流程梳理

简介&#xff1a;一份基于SpringBoot与Vue的网上书城完整项目&#xff0c;配套MySQL数据库脚本&#xff0c;主要面向计算机相关专业毕业设计学生及需要项目实战练习的Java学习者&#xff0c;解决选题难、系统不完整、无法运行等痛点。压缩包共627个文件&#xff0c;涵盖Java后端…

作者头像 李华
网站建设 2026/9/17 2:16:26

基于 Flink CDC 构建 MySQL 到 Kafka 的 Streaming ELT 整库同步管道

基于 Flink CDC 构建 MySQL 到 Kafka 的 Streaming ELT 整库同步管道 【免费下载链接】flink-cdc Flink CDC is a streaming data integration tool 项目地址: https://gitcode.com/GitHub_Trending/flin/flink-cdc 本教程以 Apache Flink CDC 项目中的 MySQL → Kafka …

作者头像 李华
网站建设 2026/9/17 2:15:35

MATLAB读取SAC地震数据:rdsac.m脚本实现与实战

简介&#xff1a;一个用于处理 SAC 格式地震数据的 MATLAB 脚本包&#xff0c;面向地震学、地球物理学领域的科研人员与技术人员&#xff0c;解决在 MATLAB 环境中直接读取和分析 SAC 文件的需求。压缩包内共 1 个文件&#xff0c;为 rdsac.m 脚本&#xff0c;体积仅 1KB。该脚…

作者头像 李华
网站建设 2026/9/17 2:14:38

嵌入式面试I2C/SPI高频考点:从协议原理到调试实战

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

作者头像 李华