Vue.js 分页功能实现详解
一、分页功能概述
1.1 什么是分页?
分页就是将大量数据分成多个页面显示,每页只显示部分数据。就像看书一样,一页一页地翻看内容。
举个例子:
- 假设你有 100 条数据
- 每页显示 10 条
- 那么就需要 10 页来显示所有数据
- 第 1 页显示:第 1-10 条
- 第 2 页显示:第 11-20 条
- 以此类推...
1.2 为什么需要分页?
- 性能优化:一次性加载所有数据会导致页面卡顿
- 用户体验:用户不需要滚动很久才能找到内容
- 网络优化:减少数据传输量
二、核心概念理解
2.1 分页的三个核心变量
① current - 当前页码
current: 1 // 表示当前在第几页,从 1 开始
- 作用:记录用户当前查看的是第几页
- 初始值:通常设置为 1(第一页)
- 变化时机:用户点击分页组件切换页码时
② pageSize - 每页显示条数
pageSize: 10 // 表示每页显示多少条数据
- 作用:控制每页显示的数据量
- 常见值:10、20、50、100
- 变化时机:用户通过下拉菜单选择不同的每页条数时
③ total - 数据总数
total: 100 // 表示总共有多少条数据
- 作用:告诉分页组件总共有多少条数据,用于计算总页数
- 计算方式:通常是数组的长度
array.length - 变化时机:数据加载或筛选后自动更新
2.2 分页计算公式
核心公式:如何计算要显示哪些数据?
假设:
- 总数据:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ...](共 25 条) - 当前页码:
current = 2 - 每页条数:
pageSize = 10
计算步骤:
-
计算起始索引(start)
start = (current - 1) * pageSize start = (2 - 1) * 10 = 10- 解释:第 2 页要从第 10 条开始(因为第 1 页已经显示了 0-9 条)
-
计算结束索引(end)
end = start + pageSize end = 10 + 10 = 20- 解释:第 2 页显示到第 20 条(不包含第 20 条,因为数组索引从 0 开始)
-
切片获取数据
paginatedList = list.slice(start, end) paginatedList = list.slice(10, 20) // 获取索引 10-19 的数据 // 结果:[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
可视化理解:
总数据:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
索引: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
第 1 页 (current=1, pageSize=10):
start = (1-1) * 10 = 0
end = 0 + 10 = 10
slice(0, 10) → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
第 2 页 (current=2, pageSize=10):
start = (2-1) * 10 = 10
end = 10 + 10 = 20
slice(10, 20) → [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
第 3 页 (current=3, pageSize=10):
start = (3-1) * 10 = 20
end = 20 + 10 = 30
slice(20, 30) → [21, 22, 23, 24, 25] // 只有 5 条,因为总共只有 25 条
三、实现步骤详解
步骤 1:在 data 中定义分页变量
位置:data() 函数中
data() {
return {
// ... 其他数据
// 分页相关
current: 1, // 当前页码,从 1 开始
pageSize: 10, // 每页显示条数
}
}
详细说明:
current: 1:初始化时显示第一页pageSize: 10:默认每页显示 10 条,可以根据需求调整
为什么从 1 开始?
- 用户习惯:用户看到的是"第 1 页"、"第 2 页",而不是"第 0 页"
- 但在计算数组索引时,需要转换为从 0 开始(通过
current - 1)
步骤 2:创建计算属性获取当前页数据
位置:computed 对象中
computed: {
// 获取当前 tab 的所有数据
currentList() {
const map = {
ch: this.ch,
jlwyq: this.jlwyq,
jlyq: this.jlyq,
db: this.db,
dbyq: this.dbyq,
qbhs: this.qbhs
}
return map[this.activeTab] || []
},
// 分页后的列表(核心逻辑)
paginatedList() {
const list = this.currentList // 获取当前 tab 的所有数据
const start = (this.current - 1) * this.pageSize // 计算起始索引
const end = start + this.pageSize // 计算结束索引
return list.slice(start, end) // 切片获取当前页的数据
},
// 分页总数
total() {
return this.currentList.length // 返回当前 tab 的数据总数
}
}
逐行解析 paginatedList:
paginatedList() {
// 第 1 步:获取完整的数据列表
const list = this.currentList
// 例如:list = [1, 2, 3, ..., 100] (100 条数据)
// 第 2 步:计算起始索引
const start = (this.current - 1) * this.pageSize
// 假设 current = 2, pageSize = 10
// start = (2 - 1) * 10 = 10
// 意思:第 2 页从索引 10 开始(即第 11 条数据)
// 第 3 步:计算结束索引
const end = start + this.pageSize
// end = 10 + 10 = 20
// 意思:第 2 页到索引 20 结束(不包含 20,即到第 20 条数据)
// 第 4 步:使用 slice 方法切片
return list.slice(start, end)
// list.slice(10, 20) 返回索引 10-19 的数据
// 结果:[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
}
为什么使用计算属性?
- 自动更新:当
current、pageSize或currentList变化时,paginatedList会自动重新计算 - 性能优化:Vue 会缓存计算结果,只有依赖变化时才重新计算
- 代码简洁:不需要手动调用函数更新数据
步骤 3:修改模板使用分页后的数据
位置:<template> 中
修改前:
<div class="list-card" v-for="(item, index) in currentList" :key="index">
<!-- 卡片内容 -->
</div>
修改后:
<div class="list-card" v-for="(item, index) in paginatedList" :key="index">
<!-- 卡片内容 -->
</div>
关键变化:
currentList→paginatedList- 现在循环的是分页后的数据,而不是全部数据
工作原理:
- 用户看到的是
paginatedList(当前页的数据) - 当用户切换页码时,
current改变 paginatedList自动重新计算- 页面自动更新显示新的数据
步骤 4:添加分页组件
位置:列表下方
<!-- 分页 -->
<div class="paging" v-if="total > 0">
<a-pagination
v-model="current"
:total="total"
:page-size="pageSize"
:show-total="(total) => `共 ${total} 条`"
show-size-changer
:page-size-options="['10', '20', '50', '100']"
@change="handlePageChange"
@showSizeChange="handlePageSizeChange"
/>
</div>
属性详解:
| 属性 | 说明 | 示例值 |
|---|---|---|
v-model="current" | 双向绑定当前页码 | 1, 2, 3... |
:total="total" | 数据总数 | 100 |
:page-size="pageSize" | 每页显示条数 | 10 |
:show-total | 显示总条数的函数 | 共 100 条 |
show-size-changer | 显示每页条数选择器 | true |
:page-size-options | 每页条数选项 | ['10', '20', '50', '100'] |
@change | 页码变化事件 | 用户点击页码时触发 |
@showSizeChange | 每页条数变化事件 | 用户选择每页条数时触发 |
v-if="total > 0" 的作用:
- 只有当有数据时才显示分页组件
- 如果没有数据,显示分页组件没有意义
步骤 5:实现分页事件处理函数
位置:methods 对象中
methods: {
// 页码变化处理
handlePageChange(page) {
this.current = page // 更新当前页码
// 滚动到顶部(可选,提升用户体验)
const contentEl = document.querySelector('.content')
if (contentEl) {
contentEl.scrollTop = 0
}
},
// 每页条数变化处理
handlePageSizeChange(current, size) {
this.pageSize = size // 更新每页条数
this.current = 1 // 重置到第一页(重要!)
}
}
handlePageChange 详解:
handlePageChange(page) {
// page 参数:用户点击的新页码,例如点击第 3 页,page = 3
// 更新当前页码
this.current = page
// 此时 current 从 2 变成 3
// paginatedList 会自动重新计算,显示第 3 页的数据
// 可选:滚动到顶部,让用户看到新页面的内容
const contentEl = document.querySelector('.content')
if (contentEl) {
contentEl.scrollTop = 0
}
}
handlePageSizeChange 详解:
handlePageSizeChange(current, size) {
// current: 当前页码(通常可以忽略)
// size: 用户选择的新每页条数,例如选择 20,size = 20
// 更新每页条数
this.pageSize = size
// 此时 pageSize 从 10 变成 20
// paginatedList 会自动重新计算,每页显示 20 条
// 重要:重置到第一页
this.current = 1
// 为什么?因为如果用户在第 3 页,然后改成每页 20 条
// 第 3 页可能没有数据了(总共只有 2 页)
// 所以重置到第 1 页更安全
}
步骤 6:在关键操作时重置页码
位置:切换 tab、搜索、重置等方法中
// 切换 tab 时重置页码
selectTab(key) {
this.activeTab = key
this.current = 1 // 重置到第一页
}
// 搜索时重置页码
search() {
this.current = 1 // 重置到第一页
this.getUserList()
}
// 重置条件时重置页码
reset() {
this.keyword = ''
this.unit = ''
this.casePolice = ''
this.current = 1 // 重置到第一页
this.getUserList()
}
四、代码逐行解析
4.1 完整代码结构
<template>
<!-- 列表显示 -->
<div class="content">
<div v-for="(item, index) in paginatedList" :key="index">
<!-- 卡片内容 -->
</div>
</div>
<!-- 分页组件 -->
<div class="paging" v-if="total > 0">
<a-pagination
v-model="current"
:total="total"
:page-size="pageSize"
@change="handlePageChange"
@showSizeChange="handlePageSizeChange"
/>
</div>
</template>
<script>
export default {
data() {
return {
// 原始数据
ch: [],
jlwyq: [],
// ... 其他数据
// 分页变量
current: 1, // 当前页码
pageSize: 10, // 每页条数
}
},
computed: {
// 获取当前 tab 的所有数据
currentList() {
// ... 根据 activeTab 返回对应数组
},
// 分页后的数据(核心)
paginatedList() {
const list = this.currentList
const start = (this.current - 1) * this.pageSize
const end = start + this.pageSize
return list.slice(start, end)
},
// 数据总数
total() {
return this.currentList.length
}
},
methods: {
// 页码变化
handlePageChange(page) {
this.current = page
},
// 每页条数变化
handlePageSizeChange(current, size) {
this.pageSize = size
this.current = 1
},
// 切换 tab(重置页码)
selectTab(key) {
this.activeTab = key
this.current = 1
}
}
}
</script>
4.2 数据流向图
用户操作
↓
触发事件(点击页码/切换tab/搜索)
↓
更新 data 中的变量(current, pageSize, activeTab)
↓
触发 computed 重新计算
↓
paginatedList 自动更新
↓
模板自动重新渲染
↓
用户看到新的页面内容
记住用户的每页条数偏好
// 使用 localStorage 保存用户选择
handlePageSizeChange(current, size) {
this.pageSize = size
this.current = 1
// 保存到本地存储
localStorage.setItem('pageSize', size)
}
// 组件创建时读取
created() {
const savedPageSize = localStorage.getItem('pageSize')
if (savedPageSize) {
this.pageSize = parseInt(savedPageSize)
}
}
分页功能的核心要点
- 三个变量:
current(当前页)、pageSize(每页条数)、total(总数) - 一个公式:
start = (current - 1) * pageSize,end = start + pageSize - 一个方法:
list.slice(start, end)获取当前页数据 - 计算属性:使用
computed自动响应数据变化 - 事件处理:处理页码和每页条数变化
- 重置逻辑:关键操作时重置到第 1 页
组件核心
<a-pagination
:current="current"
:page-size="pageSize"
:total="total"
/>