vue_分頁元件

Zswsown發表於2020-10-05

封裝的分頁元件的結構如下:
在這裡插入圖片描述

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

相關文章