首頁>技術>

前言

web專案在由混合渲染演變成前後端完全分離之後,很多功能的實現也越來越倚重於前端,如我們接下來要談到的資料分頁控制。在典型的資料分頁控制組件中,我們需要知道資料的當前偏移量(也可以叫當前頁碼,兩者之間可以進行簡單轉換)、資料總數、每頁展示資料數。當然還有當前頁碼的自定義css類,渲染模板等,這個暫且不討論,我們只實現核心的功能:資料分頁導航。下圖是本文最終要實現的效果預覽:

解釋一下上圖的導航工作原理:我們將分頁導航分為5部分,從左到右依次為:前向、左中、當前、右中、後向。

左中和右中部分會隨著當前頁碼的變化而呈現不同的展示方式,但它們兩者邏輯是相同的,主要是邊界的判定。以左中為例:當前向和當前之間的頁碼數不多於三個時,完全顯示中間的所有頁碼,如下圖:

當前向和當前之間的頁碼數多於三個時,左中第一個頁碼用…代替,表示前向和左中部分有更多未展開頁碼。

前向和後向的展示就比較簡單了:兩者的上頁"<"和下頁">"標識會永遠展示,前向部分的頁碼1只有噹噹前頁碼不是1時才展示;後向部分的總數頁碼只有噹噹前頁碼不是總頁碼時才展示。

元件原型
<app-pagination :total="200" :size="10"></app-pagination>

我們為分頁元件命名為app-pagination,接受兩個引數:total和size,分別對應於前言所述的資料總數和每頁展示資料數。註冊為vue的元件:

Vue.component('app-pagination', {    props: {        total: {type: Number},        size: {type: Number}    },    data() {        return {            total: this.total,            size: this.size        };    },    template: `    <ul v-if="pages > 1" class="pagination">        <li><a @click="navigate(current-1 < 1 ? 1 : current-1)"><</a></li>        <li v-if="current != 1"><a @click="navigate(1)">1</a></li>        <li v-for="p in prevs">            <a v-if="'...' != p" @click="navigate(p)">{{p}}</a>            <span v-else>{{p}}</span>        </li>        <li class="active">{{current}}</li>        <li v-for="p in nexts">            <a v-if="'...' != p" @click="navigate(p)">{{p}}</a>            <span v-else>{{p}}</span>        </li>        <li v-if="current != pages"><a @click="navigate(pages)">{{pages}}</a></li>        <li><a @click="navigate(current+1 > pages ? pages : current+1)">></a></li>    </ul>`})

在template部分,我們對元件模板進行了分段判斷和定義,涉及到需要實現的引數和方法如下:pages、current、prevs、nexts、navigate。

計算pages

pages表示當前資料可分頁總數,我們在元件中增加一段computed配置,增加pages獲取方法:

...computed: {    pages() {        return Math.ceil(this.total/this.size);    }},...
獲取current引數

current引數也即當前頁碼,為了從設計上最簡化和目前大多數傳參命名習慣,我們預設瀏覽器中的引數page即為當前頁碼,以這個url為例:http://example.com/news?category=1&page=2,我們需要從中提取出page引數,我們在methods部分定義一個獲取頁碼引數的方法param:

methods: {    param(name = null) {        let url = location.href.split('?');        let params = [];        if(url && url[1]) {            let p = url[1].split('&');            for(let i = 0; i < p.length;i++) {                let kv = p[i].split('=');                params[kv[0]] = kv[1];            }        }        return name ? params[name] : params;    }},

在computed中增加current方法:

current() {    let page = parseInt(this.param('page'));    return page > 1 ? page : 1;},
prevs和nexts的實現

在computed中增加prevs和nexts方法,兩者均需要處理好邊界問題,保證不越界,並在超出部分用…替代:

prevs() {    let data = [];    for(let i = 2; i >= 1; i--) {        if(this.current - i > 1) data.push(this.current - i);    }    if(data[0] && data[0] > 1) {        if(data[0] - 1 > 2) data.unshift('...');        else if(data[0] - 1 > 1) data.unshift(data[0] - 1);    }    return data;},nexts() {    let data = [];    for(let i = 2; i >= 1; i--) {        if(this.current + i < this.pages) data.push(this.current + i);    }    if(data[0] && data[0] < this.pages) {        if(data[0] + 1 < this.pages) data.unshift('...');    }    return data.reverse();}
事件navigate的處理

在methods中增加如下方法:

navigate(page) {    let params = this.param(), query = '';    params['page'] = page;    Object.keys(params).forEach(k => query += k+'='+encodeURIComponent(params[k])+'&');    location.href = location.href.split('?')[0] + '?' + query.slice(0, -1);}

這樣保證當相應的頁碼被點選後,動態修改當前url中的page引數,重新整理頁面。

簡單的樣式修飾
.pagination li{display:inline-block;padding:5px;}.pagination li a{color:gray;}.pagination li.active{color:#32d296;}

給你程式碼往期回顧:

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • OpenShift 4 之Istio-Tutorial (10) 訪問白名單、黑名單