徒手擼UI之Paginator

QingUI是一個UI組件庫

目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, Checkbox, Radio, Switch, InputNumber, Input

ES6語法編寫,無依賴

原生模塊化,Chrome63以上支持,請開啓靜態服務器預覽效果, 靜態服務器傳送門

採用CSS變量配置樣式

辛苦造輪子,歡迎來github倉庫star: https://github.com/veedrin/qing

四月份找工做,求內推,座標深圳

寫在前面

去年年末項目中嘗試着寫過一個分頁的Angular組件,而後就有了寫QingUI的想法javascript

過程仍是很是有意思的前端

接下來我會用幾篇文章分別介紹每一個組件的大概思路,請你們耐心等待java

這一篇介紹Paginator分頁git

最重要的,求star,求fork,求內推github

repo: QingUI

少廢話,先上圖

img failed

爲何要有分頁

通常的需求是,我有一個列表,可是我不想一下讓用戶看這麼多,一次看一點,再想看,翻到下一頁後端

固然如今有無限滾動,只要滾動到必定距離,就給你加載新的數據,這個咱們不考慮數組

分頁也有兩種作法,一種是一次性加載全部數據,前端作分頁;一種是每次加載一部分,點擊分頁就是觸發再次加載的動做服務器

第一種作法應該不多見了吧,首次加載的壓力太大模塊化

分頁怎麼工做

頁面初始加載的時候向後臺請求數據,請求哪些數據呢?要顯示的列表信息,還有當前是第幾頁函數

若是每頁顯示多少條是可配置的,那麼還須要每頁顯示多少條和總條數

初始加載確定是第一頁

而後用戶看完第一頁,往下翻,多是翻到第二頁,也多是翻到後面的任一頁,無所謂

咱們獲取到用戶想翻到第幾頁的信息之後,傳給後端,後端再把相應頁的列表信息傳過來,前端展現

注意,這個時候分頁是要變的,用戶點擊的那一頁要高亮,以前那一頁去掉高亮,若是頁數比較多,省略號的位置也要根據規則發生變化

因此咱們得出一個重要信息,分頁組件展現頁碼的那一塊每次點擊都是要從新渲染的

$bar就是展現頁碼的容器,展現頁碼的模板封裝到另外一個函數裏

一開始能想到這個,後面就不須要推倒重來了,你猜我有沒有推倒重來 :)

tpl += `
    <div class="square end prev">﹤</div>
    <div class="bar"></div>
    <div class="square end next">﹥</div>
`;

數據模型

若是咱們把展現邏輯放到模板渲染函數裏,那模板渲染函數會變得很是繁雜

咱們能夠分紅兩步,第一步構建數據模型,第二步根據數據模型生成模板

我仔細的觀察過GitHub(GitHub已經很是優美了)的分頁邏輯,QingUI的分頁邏輯就是根據GitHub來的

我總結了一下,代碼註釋裏也有:

  • 首頁和尾頁必須展現
  • 若是有省略號則首尾只展現一條,當前頁先後各展現兩條共五條,一邊沒有空間則疊加到另外一邊
  • 首尾頁與當前頁五條能夠重合
  • 跨度大於等於兩條纔出現省略號,省略號用0表示

哦,忘了解釋,數據模型是怎麼映射的

分頁都是從1開始,最大隨意(通常不會太大),因此咱們構建一個數組,1到正無窮就表明1到正無窮頁,0表明省略號

總頁數在1到7頁之間

1到7頁之間能夠徹底展現,爲何?

首尾各1頁,中間共5頁,加起來就是7頁,超過7頁就會有省略號

不是說跨度大於等於2頁纔會有省略號嗎?

由於首頁和中間的5頁是能夠重合的,若是有8頁,前面5頁和最後1頁中間正好隔了2頁

因此1到7頁之間能夠徹底展現

for (let i = 1; i <= c; i++) {
    this.model.push(i);
}

總頁數7頁以上且當前頁小於4

若是當前頁小於4,至少要保證當前頁加左右至少有5頁,因此這種狀況要單獨拎出來

後面再加一個省略號,以及尾頁

for (let i = 1; i <= 5; i++) {
    this.model.push(i);
}
this.model.push(0, c);

總頁數7頁以上且當前頁小於6

這種狀況就是首頁和中間5頁不重合的狀況,因此for循環不須要寫死

一樣,後面再加一個省略號,以及尾頁

for (let i = 1; i <= p + 2; i++) {
    this.model.push(i);
}
this.model.push(0, c);

總頁數7頁以上且當前頁小於總頁數減4

這種狀況就是距離首頁的跨度大於等於2,距離尾頁的跨度也大於等於2,因而先後都有省略號

this.model.push(1, 0);
for (let i = p - 2; i <= p + 2; i++) {
    this.model.push(i);
}
this.model.push(0, c);

總頁數7頁以上且當前頁小於總頁數減1

這種狀況是說後面沒有省略號了,可是也不至於和尾頁產生重合

this.model.push(1, 0);
for (let i = p - 2; i <= c; i++) {
    this.model.push(i);
}

總頁數7頁以上且當前頁等於總頁數減1或者等於總頁數

中間5頁與尾頁產生重合了,至少要保證渲染出5頁,因此for循環寫死

this.model.push(1, 0);
for (let i = c - 4; i <= c; i++) {
    this.model.push(i);
}

總結

6種狀況:

  • 沒有省略號
  • 前面有省略號可是中間5頁與首頁重合
  • 前面有省略號且中間5頁與首頁不重合
  • 前面和後面都有省略號
  • 後面有省略號且中間5頁與尾頁不重合
  • 後面有省略號可是中間5頁與尾頁重合

仍是挺有規律的是吧

數據模型代碼

buildModel() {
    // 每次從新初始化
    this.model = [];
    const c = this.pageCount, p = this.position;
    if (c < 8) {
        for (let i = 1; i <= c; i++) {
            this.model.push(i);
        }
    } else {
        if (p < 4) {
            for (let i = 1; i <= 5; i++) {
                this.model.push(i);
            }
            this.model.push(0, c);
        } else if (p < 6) {
            for (let i = 1; i <= p + 2; i++) {
                this.model.push(i);
            }
            this.model.push(0, c);
        } else {
            if (p < c - 4) {
                this.model.push(1, 0);
                for (let i = p - 2; i <= p + 2; i++) {
                    this.model.push(i);
                }
                this.model.push(0, c);
            } else if (p < c - 1) {
                this.model.push(1, 0);
                for (let i = p - 2; i <= c; i++) {
                    this.model.push(i);
                }
            } else {
                this.model.push(1, 0);
                for (let i = c - 4; i <= c; i++) {
                    this.model.push(i);
                }
            }
        }
    }
}

若是你不喜歡GitHub分頁規則,或者本身有特殊的需求

能夠根據上面的規律本身定製一套分頁邏輯

真的,往上套就能夠了

渲染

數據模型都構建出來了,渲染就簡單了

for (const item of this.model) {
    if (item > 0) {
        if (this.position !== item) {
            tpl += `<div class="square page">${item}</div>`;
        } else {
            tpl += `<div class="square page active">${item}</div>`;
        }
    } else {
        tpl += '<div class="square gap">···</div>';
    }
}

prev和next置灰

在某些狀況,咱們要讓用戶知道往前或者日後點擊是無效的,要進行置灰處理

規則也挺簡單的

若是當前頁是第1頁

if (this.position === 1) {
    this.$prev.classList.add('disabled');
    this.$next.classList.remove('disabled');
}

若是當前頁是最後1頁

if (this.position === this.pageCount) {
    this.$next.classList.add('disabled');
    this.$prev.classList.remove('disabled');
}

若是當前頁既不是第1頁也不是最後1頁

if (this.position === this.pageCount) {
    this.$prev.classList.remove('disabled');
    this.$next.classList.remove('disabled');
}

若是總頁數是1

這種狀況很容易被忽略

若是總共只有1頁,那左右都點不了,並且當即返回

if (this.pageCount === 1) {
    this.$prev.classList.add('disabled');
    this.$next.classList.add('disabled');
    return;
}

能夠配置每頁顯示多少條

這裏主要是注意一個問題

假如如今的當前頁是比較靠後的位置

而後我增長每頁顯示的條數,那勢必總頁數就變小了

有可能總頁數變的比當前頁還小

那麼這個時候就只能強制改變當前頁,讓它變成最後1頁了

能夠自由跳轉

這就是一個輸入框,加keyup監聽Enter鍵的事件

寫在後面

Paginator比較核心的邏輯就在這裏了

最有意思的是構建數據模型的那一段,挺費腦子的

下一篇文章介紹Tree,敬請期待

最後,求star,求fork,求內推

repo: QingUI
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息