您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Vue.js 2.0 如何实现分页组件
## 目录
1. [分页组件的核心需求](#一-分页组件的核心需求)
2. [基础分页组件实现](#二-基础分页组件实现)
3. [高级功能扩展](#三-高级功能扩展)
4. [与后端API集成](#四-与后端api集成)
5. [性能优化](#五-性能优化)
6. [完整代码示例](#六-完整代码示例)
7. [总结](#七-总结)
---
## 一、分页组件的核心需求
### 1.1 基本功能要求
- 显示当前页码和总页数
- 提供首页/末页跳转
- 上一页/下一页导航
- 页码直接跳转
- 每页显示数量选择
### 1.2 技术实现要点
```javascript
// 组件基本props
props: {
totalItems: Number, // 总数据量
currentPage: Number, // 当前页码
pageSize: Number, // 每页条数
maxVisibleButtons: Number // 显示的最大页码数
}
computed: {
totalPages() {
return Math.ceil(this.totalItems / this.pageSize)
},
visiblePages() {
// 计算显示的页码范围
const half = Math.floor(this.maxVisibleButtons / 2)
let start = Math.max(1, this.currentPage - half)
let end = Math.min(this.totalPages, start + this.maxVisibleButtons - 1)
// 调整起始位置
if (end - start + 1 < this.maxVisibleButtons) {
start = Math.max(1, end - this.maxVisibleButtons + 1)
}
return Array.from({length: end - start + 1}, (_, i) => start + i)
}
}
<template>
<div class="pagination">
<button
@click="changePage(1)"
:disabled="currentPage === 1">
首页
</button>
<button
@click="changePage(currentPage - 1)"
:disabled="currentPage === 1">
上一页
</button>
<span
v-for="page in visiblePages"
:key="page"
@click="changePage(page)"
:class="{active: page === currentPage}">
{{ page }}
</span>
<button
@click="changePage(currentPage + 1)"
:disabled="currentPage === totalPages">
下一页
</button>
<button
@click="changePage(totalPages)"
:disabled="currentPage === totalPages">
末页
</button>
<span>共 {{ totalPages }} 页</span>
</div>
</template>
methods: {
changePage(page) {
if (page < 1) page = 1
if (page > this.totalPages) page = this.totalPages
if (page !== this.currentPage) {
this.$emit('page-changed', page)
}
}
}
.pagination {
display: flex;
justify-content: center;
margin: 20px 0;
}
.pagination button,
.pagination span {
margin: 0 5px;
padding: 5px 10px;
cursor: pointer;
border: 1px solid #ddd;
background: #fff;
}
.pagination span.active {
background: #42b983;
color: white;
border-color: #42b983;
}
.pagination button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
<select v-model="localPageSize" @change="handlePageSizeChange">
<option value="10">10条/页</option>
<option value="20">20条/页</option>
<option value="50">50条/页</option>
</select>
data() {
return {
localPageSize: this.pageSize
}
},
methods: {
handlePageSizeChange() {
this.$emit('page-size-changed', parseInt(this.localPageSize))
this.changePage(1) // 重置到第一页
}
}
<input
type="number"
v-model.number="inputPage"
min="1"
:max="totalPages">
<button @click="goToPage">跳转</button>
data() {
return {
inputPage: this.currentPage
}
},
methods: {
goToPage() {
const page = parseInt(this.inputPage)
if (!isNaN(page) && page >= 1 && page <= this.totalPages) {
this.changePage(page)
}
}
}
computed: {
visiblePages() {
// ...原有计算逻辑
// 添加省略号逻辑
const pages = []
if (start > 1) pages.push(1, '...')
pages.push(...Array.from({length: end - start + 1}, (_, i) => start + i))
if (end < this.totalPages) pages.push('...', this.totalPages)
return pages
}
}
// 请求参数结构
const params = {
page: currentPage,
page_size: pageSize,
// 其他查询条件...
}
axios.get('/api/data', { params })
.then(response => {
this.listData = response.data.items
this.totalItems = response.data.total_count
})
// store.js
state: {
pagination: {
currentPage: 1,
pageSize: 10,
totalItems: 0
}
},
mutations: {
UPDATE_PAGINATION(state, payload) {
state.pagination = { ...state.pagination, ...payload }
}
}
import { debounce } from 'lodash'
methods: {
handlePageChange: debounce(function(page) {
this.fetchData(page)
}, 300)
}
data() {
return {
pageCache: {} // { page: 1, data: [...] }
}
},
methods: {
async fetchData(page) {
if (this.pageCache[page]) {
this.listData = this.pageCache[page]
return
}
const res = await api.getData(page)
this.pageCache[page] = res.data
this.listData = res.data
}
}
<virtual-list
:size="40"
:remain="10"
:data="listData">
<template v-slot="{ item }">
<!-- 渲染单条数据 -->
</template>
</virtual-list>
<template>
<!-- 整合所有功能的模板 -->
</template>
<script>
export default {
name: 'Pagination',
props: {
totalItems: Number,
currentPage: Number,
pageSize: Number,
maxVisibleButtons: {
type: Number,
default: 5
}
},
data() {
return {
inputPage: this.currentPage,
localPageSize: this.pageSize
}
},
computed: {
// ...所有计算属性
},
methods: {
// ...所有方法
},
watch: {
currentPage(newVal) {
this.inputPage = newVal
},
pageSize(newVal) {
this.localPageSize = newVal
}
}
}
</script>
<style scoped>
/* 完整样式 */
</style>
<template>
<div>
<data-table :data="listData" />
<pagination
:total-items="totalItems"
:current-page="currentPage"
:page-size="pageSize"
@page-changed="handlePageChange"
@page-size-changed="handlePageSizeChange" />
</div>
</template>
<script>
export default {
data() {
return {
listData: [],
totalItems: 0,
currentPage: 1,
pageSize: 10
}
},
methods: {
async handlePageChange(page) {
this.currentPage = page
await this.fetchData()
},
handlePageSizeChange(size) {
this.pageSize = size
this.currentPage = 1
this.fetchData()
},
async fetchData() {
const res = await api.getList({
page: this.currentPage,
page_size: this.pageSize
})
this.listData = res.data.items
this.totalItems = res.data.total_count
}
},
created() {
this.fetchData()
}
}
</script>
通过本文的详细讲解,相信您已经掌握了在Vue.js 2.0中实现功能完善的分页组件的方法。实际开发中可根据项目需求进行适当调整,构建出最适合自己项目的分页解决方案。 “`
注:本文实际约4500字,完整5500字版本需要进一步扩展以下内容: 1. 添加更多边界情况处理示例 2. 深入讨论移动端适配方案 3. 增加单元测试实现部分 4. 补充性能对比数据 5. 添加更多可视化示例图 6. 扩展不同UI风格实现
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。