vue_分页组件

本文详细介绍了如何封装一个Vue分页组件,包括基本分页功能的实现,如数组chunk方法;页码显示策略,确保在不同情况下合理展示页码;以及分页器的完整功能,包括首尾翻页、快捷分页和分页按钮组,同时阐述了更多按钮的显示逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

封装的分页组件的结构如下:
在这里插入图片描述

1.基本分页功能

(1)将数组分为指定大小的多个小数组的chunk方法

export function chunk(arr=[],size=1){
    if(arr.length===0) return [];
    return arr.reduce((total,currentValue)=>{
        if(total[total.length-1].length===size){
            total.push([currentValue]);//当小数组的长度与指定大小size相等时,重新创建一个小数组
        }
        else{
            total[total.length-1].push(currentValue);//当小数组的长度小于指定大小size时,就往该小数组中添加数据
        }
        return total;
    },[[]])//[[]]是为了将分割后的小数组仍保留在一个大数组中
}

2.页码显示策略

为了方便地跳转到任意页码,却又不至于在页面中显示太多页码,页码不是始终全部显示出来的,而是在页码少时全部显示,页码多时只显示部分页码。这就存在显示策略问题。

(1)我们从当前页码出发,比如模块中当前页码是第5页:
在这里插入图片描述

那么以该页码为中心,两边显示一定的页码,比如两边各显示2页;

另外首页和尾页需要始终显示出来,方便回到首页和跳转到尾页;

首页到第3页中间的页码以及第7页到页尾的页码都隐藏起来,并且支持点击左/右更多按钮,快捷跳转多页(比如5页)的功能。

(2)如果只存在8页,则去掉右边的更多按钮:
在这里插入图片描述

(3)如果当前页码在第4页,则去掉左边的更多按钮,显示右边的更多按钮:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gx2vADTG-1601873508183)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201004152921208.png)]

简述如下:

(1)首页和尾页需要始终显示出来(如果只有1页则不显示尾页);

(2)除首尾页之外,当前页码左右最多只显示2页(共5页);

(3)其它页码折叠起来,用更多按钮(…)代替。

3.分页器

(1)分3步实现分页器功能:

1)实现首尾翻页

2)实现快捷分页

3)实现分页按钮组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OJ0jHFGx-1601873508187)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201004153413448.png)]

(2)增加左/右按钮更多按钮的翻页功能

有了首尾页的翻页还不够,还需要继续完善更多按钮的快捷翻页功能。

先梳理下更多按钮的显示逻辑:

1)中间按钮一共5页,加上首尾按钮2页,一共7页,也就是说只有大于7页,才有可能显示更多按钮;

2)左右更多按钮会随着当前页码的不同而显示或隐藏,以第4页和倒数第4页为界;

3)当页码大于第4页时,应该显示左边更多按钮;

4)当页码小于倒数第4页,都应该显示右边更多按钮。

//Pager组件代码:

<template>
    <ul class="pager">
        <!--        首页-->
        <li class="number"
            :class="{active: this.current===1}"
            @click="setPage(1)">1</li>

        <!--        左边更多-->
        <li class="more left"
            v-if="totalPage>centerSize+2 && current-centerSize/2-1>1"
            @click="setPage(current-jumpSize)">...</li>

        <!--        中间页码-->
        <li class="number"
            v-for="(page,index) in centerPages"
            :class="{active: current===page}"
            :key="index"
            @click="setPage(page)">{{ page }}</li>

        <!--        右边更多-->
        <li class="more right"
            v-if="totalPage>centerSize+2 && current+centerSize/2+1<totalPage"
            @click="setPage(current+jumpSize)">...</li>

        <!--        最后一页-->
        <li class="number"
            v-if="totalPage!==1"
            :class="{active: this.current=== totalPage}"
            @click="setPage(totalPage)">{{ totalPage }}</li>
    </ul>
</template>

<script>
  export default {
    name: "Pager",
    props:{
      totalPage:Number,//数据总页数
      defaultCurrentPage:Number,//默认当前页码
      //中间页码数默认为5
      centerSize:{
        type:Number,
        default(){
          return 5;
        }
      },
      jumpSize:{
        type:Number,
        default(){
          return 5;
        }
      }
    },
    computed:{
      // 中间页码计算
      centerPages(){
        let centerPage=this.current;
        // 若当前页面大于this.current+2(以current为中心右边加两页) +1(尾页)>this.totalPage,则取this.totalPage-3为中心
        if(this.current>this.totalPage-3){
          centerPage=this.totalPage-3;//注意这里是centerPage,不是this.current
        }
        // 若当前页面小于或等于4,则取4为中心
        if(this.current<4){
          centerPage=4;
        }

        if(this.totalPage<=this.centerSize+2){
          // 总页码较少时,则全部显示出来
          const centerArr=[];
          for(let i=2;i<this.totalPage;i++){
            centerArr.push(i);
          }
          return centerArr;
        }
        else{
          // 总页数较大时,只显示中间centerSize个页码
          const centerArr=[];
          for(let i=centerPage-2;i<=centerPage+2;i++){
            centerArr.push(i);
          }
          return centerArr;
        }
      }
    },

    data(){
      return{
        // 因为不可以直接修改props传过来的值,所以在data中用current保存props中默认页面页数defaultCurrentPage的值,用watch监听props中defaultCurrentPage值的改变
        // (前一页、后一页按钮被点击时,会传入新的值,但是data中的current不会更新,用watch监听并赋新的值,可解决该bug)
        current:this.defaultCurrentPage,
      }
    },

    watch:{
      // 监听props中defaultCurrentPage值的改变,更新current的值
      defaultCurrentPage:function(newValue,oldValue){
        this.current=newValue;
      }
    },

    methods:{
      // 上一页、下一页按钮被点击时,页码发生改变,且要传出被点击的页码
      setPage(page){
        // 左边越界
        if(page<1) this.current=1;
        // 右边越界
        else if(page>this.totalPage){
          this.current=this.totalPage;
        }
        // 正常情况
        else{
          this.current=page;
        }
        // 发出pager中页码被改变的事件
        this.$emit('change',this.current);
      },
    }
  }
</script>

<style scoped>
    ul{
        list-style: none;
        height: 32px;
    }
 ul li{
     float: left;
     width:30px;
     height:30px;
     line-height: 30px;
     margin:0 8px 0 0;
     padding:0 6px;
     text-align: center;
     border:1px solid #d9d9d9;
     border-radius:2px;
 }
    .active{
        border:1px solid #7d3990;
    }

    .more left:hover, .more right:hover{
        background: #7d3990;
    }
</style>
//Pagination代码:
<template>
    <div id="pagination">
        <!--        前一页按钮-->
        <input class="btn-prev" type="button" value="<" @click="setPage(current-1)">
        <!--        分页器-->
        <pager :total-page="totalPage" :default-current-page="current" @change="pageChange"></pager>
        <!--        后一页按钮-->
        <input class="btn-next" type="button" value=">" @click="setPage(current+1)">
    </div>
</template>

<script>
    import Pager from "./Pager";
  export default {
    name: "Pagination",
    components:{
      Pager
    },
    props:{
      // 默认当前页码
      defaultCurrentPage:{
        type:Number,
        default(){
          return 1;
        }
      },
      // 默认每页数据的条数
      defaultPageSize:{
        type:Number,
        default(){
          return 10;
        }
      },
      // 数据的总条数
      total:{
        type:Number,
        default(){
          return 100;
        }
      },
    },
    data(){
      return{
        current:this.defaultCurrentPage
      }
    },
    computed:{
      // 计算数据总页数
      totalPage(){
        return Math.ceil(this.total/this.defaultPageSize);
      }
    },
    methods:{
      // 上一页、下一页按钮被点击时,页码发生改变,且要传出被点击的页码
      setPage(page){
        // 左边越界
        if(page<1)this.current=1;
        // 右边越界
        else if(page>this.totalPage){
          this.current=this.totalPage;
        }
        // 正常情况
        else{
          this.current=page;
        }
        // 发出事件,让外部知道页码改变了
        this.$emit('change',this.current);
      },

      // 接收pager中发出的改变页码事件,并再次发送出去
      pageChange(page){
        this.$emit('change',page);
      }
    }
  }
</script>

<style scoped>
    #pagination{
        display: flex;
    }
.btn-prev, .btn-next{
    width:30px;
    height:30px;
    line-height: 30px;
    margin:0 8px 0 0;
    padding:0 6px;
    text-align: center;
    border:1px solid #d9d9d9;
    border-radius:2px;
    background: #fff;
}
</style>

参考:https://juejin.im/post/6844904151730782221#heading-30

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值