分页组件
知识点
attrs和props的区别
setup( props , { emit , attrs , slots } ){ //props 接受父组件的传值 // emit 给父组件派发事件 // attrs 接受父组件传值(除了props以外的属性) // slots 接受父组件的插槽内容 }
目的:封装一个统一的分页组件
实现业务
页面显示5一页
可以设置每页多少条,根据后端返回的总数据,可以渲染出总页数
点击切换页码实现样式高亮,并调用接口获取当前页码的数据
点击上一页下一页按钮可以实现页码切换并调用接口切换当前页码的数据
当点击到第一页或者最后一页时候,上一页或下一页按钮被禁用
当当前页码大于3时,左侧显示...
当当前页码小于总页码-2时,右侧显示...
落地代码
-
基本结构和样式
<template> <div class="xtx-pagination"> <a href="javascript:;" class="disabled">上一页</a> <span>...</span> <a href="javascript:;" class="active">3</a> <a href="javascript:;">4</a> <a href="javascript:;">5</a> <a href="javascript:;">6</a> <a href="javascript:;">7</a> <span>...</span> <a href="javascript:;">下一页</a> </div> </template> <script> export default { name: 'XtxPagination' } </script> <style scoped lang="less"> .xtx-pagination { display: flex; justify-content: center; padding: 30px; > a { display: inline-block; padding: 5px 10px; border: 1px solid #e4e4e4; border-radius: 4px; margin-right: 10px; &:hover { color: @xtxColor; } &.active { background: @xtxColor; color: #fff; border-color: @xtxColor; } &.disabled { cursor: not-allowed; opacity: 0.4; &:hover { color: #333 } } } > span { margin-right: 10px; } } </style>
-
父组件传入后端返回的 total 总条数,每页显示多少条 pageSize , 当前默认的页码 page,计算出动态的分页列表
父组件
<XtxPagination :total='100',:page='1'/>
子组件
<template> <div class="xtx-pagination"> <a href="javascript:;" :class="{disabled:page===1}" @click='changePage(page-1)'>上一页</a> <span v-if='page>3'>...</span> <a href="javascript:;" :class="{active:page===item}" v-for='item in list' :key='item' @click='changePage(item)'>{{item}}</a> <span v-if='page<totalPage-2'>...</span> <a href="javascript:;" :class="{disabled:page===totalPage}" @click='changePage(page+1)'>下一页</a> </div> </template>
import { computed, ref } from 'vue' export default { name: 'XtxPagination', props: { total: { type: Number, required: true }, pagesize: { type: Number, default: 10 } }, setup (props, { emit, attrs }) { // attrs表示父组件传递的属性,但是不是props,并且attrs的值不是响应式的 // 计算页码 // 数据的总条数 // 每页的条数 // 当前页码 const page = ref(attrs.page || 1) // 总页数 const totalPage = Math.ceil(props.total / props.pagesize) // 动态计算页码的列表 const list = computed(() => { const pages = [] if (totalPage <= 5) { // 开始的数据 for (let i = 1; i <= totalPage; i++) { pages.push(i) } } else { if (page.value <= 3) { // 开始的数据 for (let i = 1; i <= 5; i++) { pages.push(i) } } else if (page.value >= totalPage - 2) { // 结束的数据 for (let i = totalPage - 4; i <= totalPage; i++) { pages.push(i) } } else { // 中间的数据 for (let i = page.value - 2; i <= page.value + 2; i++) { pages.push(i) } } } return pages }) // 切换页码:修改父组件的当前页码 const changePage = (currentPage) => { // 防止点击上一页和下一页时超出范围 if (currentPage <= 0 || currentPage > totalPage) return page.value = currentPage // 触发接口调用 emit('change-page', currentPage) } return { list, changePage, totalPage, page } } }
-
父组件内接受事件和参数进行接口调用获取数据
<XtxPagination :total='100',:page='1' @change-page='changePage'/>
export default { setup(){ ...省略代码 // 筛选条件准备 const reqParams = reactive({ // 当前页码 page: 1, // 每页的条数 pageSize: 10, // 是否有图片 hasPicture: null, // 筛选条件 tag: null, // 排序的字段 sortField: null }) // 更新当前页码 const changePage=(page)=>{ reqParams.page=page } //侦听器侦听数据的变化调用接口 watch( reqParams ,()=>{ //接口调用 // 获取评论列表 findCommentListByGoods(goods.value.id, reqParams).then(res => { total.value = res.result.counts// 获取总数 list.value = res.result.items// 评论列表 }) },{ immediate:true }) return{ changePage } } }