簡單封裝分頁功能pageView.js

發表於2016-08-21

閱讀目錄

分頁是一個很簡單,通用的功能。作為一個有經驗的前端開發人員,有義務把程式碼中類似這樣公共的基礎性的東西抽象出來,一來是改善程式碼的整體質量,更重要的是為了將來做類似的功能或者類似的專案,能減少不必要的重複工作量。在實際專案中,尤其是網站型別的專案中,分頁部分的設計總是個性化比較強,基本上都不會長的一樣,所以可能之前抽象出來的東西,如果寫的不夠靈活的話,對這些個性化強的專案來說,可能直接應用的時候也得做些調整才行。本文嘗試提供一個儘量滿足這兩方面要求的分頁元件。

先介紹下寫這個東西的背景:一直以來,我都想寫一個相對比較靈活簡單的列表元件,去年寫過一個版本,後來改了幾次,現在已經用到好幾個專案裡面去了,重構起來也有不少的工作量,因為應用到的頁面已經把比較多了,所以就沒有輕易地去做這個事情。最近的工作,涉及到一個相對簡單的列表頁面,然後給的時間也比較多,於是我準備趁這個時候把我一直想寫的列表元件給寫出來。現有的那個列表管理元件,沒有做好職責分離,列表的管理跟分頁的管理是揉在一起的,程式碼也比較亂,所以這次我打算先從分頁元件下手。因為分頁元件與列表之間並沒有太多耦合的邏輯,所以當把它們分離出來的時候,程式碼會更加清晰,獨立,將來要維護也方便些。前端雖然做不到像後臺那樣,考慮那麼多的設計模式,但要是能把程式碼寫的更讓人容易理解的話,對團隊對公司來說,真的是一件很好的事情。

雖然網上有不少的分頁外掛,但是都不值得去用,一來是有輕微的學習成本,二來是不符合自己的封裝的思想,看著彆扭;而且像這樣簡單的封裝,最適合自己動手去寫,加強物件導向程式設計的鍛鍊了。

下面就開始這個分頁元件的內容。

基本思想

先來說下我的基本想法。分頁這個部分,從內容上可能包括有:上一頁,首頁,下一頁,尾頁以及具體頁;頁碼輸入跳轉;分頁大小;記錄總數;記錄範圍等;從結構上,必須知道分頁大小,當前頁的索引以及記錄總數才能構造所有的內容;從操作上:改變分頁大小,或者是點選上一頁,首頁,下一頁,尾頁以及具體頁,或者是直接輸入頁碼,都會引發外部分頁內容的拉取。對外部來說,不管分頁部分做什麼操作,只要在這些操作之後,通知外部去拉取即可,分頁只需要提供一個簡單的api給外部,告訴它們當前的分頁大小和頁碼;但是在外部拉取到新的內容之後,還得做一件事情,就是要根據最新的記錄總數,去更新分頁部分的UI,前面說分頁的內容需要記錄總數,頁碼和分頁大小才能構造出來。由於頁碼跟分頁大小都屬於分頁內部管理的,所以外部更新分頁UI的時候,只需要告訴分頁最新的記錄數就夠了。以上就是分頁元件跟外部功能互相互動時候的唯一場景,基於這些,就可以把所以把分頁相關的東西都封裝起來,給外部提供幾個簡單的api來實現它們之間的呼叫關係,最終完成我們需要的分離的目的。

效果演示

方便大家看到這個東西的實際用法跟效果,我模擬真實的場景,寫了一個簡單的demo,一起來看看。

demo效果:

image

demo地址:

http://liuyunzhuge.github.io/blog/form/dist/html/pageView.html

pageView相關css:

https://github.com/liuyunzhuge/blog/blob/master/form/src/css/page_view.css

pageView.js原始碼:

https://github.com/liuyunzhuge/blog/blob/master/form/src/js/mod/pageView.js

demo相關的原始碼:

https://github.com/liuyunzhuge/blog/blob/master/form/src/js/app/pageView.js

原始碼部分也可以直接開啟demo地址,通過chrome的開發者工具來檢視,因為這些程式碼放在git上面,是跟我以前的程式碼放在一塊的,怕不知道的人還以為這麼個小東西,還需要寫那麼多個檔案。再補充下其它方面的說明:這些程式碼都是用seajs管理的,然後整個pageView.js是用我自己之前寫的一個用來做js的物件導向程式設計的模組class.js方式開發的,可能沒了解過的人,不知道它是做什麼用,關於它的介紹都在下面這篇文章裡面:

詳解Javascript的繼承實現

DEMO解析

直接看我在demo裡,完成那個頁面的核心程式碼:

無標題

從上面的程式碼也能看出,這個分頁元件最核心的api也就是下面幾個:

getParams():它是一個例項方法,返回元件的分頁大小跟頁碼,至於這兩個值的引數名字,可以通過option來修改;

refresh(total):這也是一個例項方法,外部傳給它一個最新的記錄總數,分頁元件再根據它重新渲染UI;

onChange:這是一個函式型別的回撥,它可以作為一個option在建立例項的時候傳入,所有分頁操作都會反饋到這個回撥裡面來,通常只要把外部拉取內容的動作繫結它上面即可。

考慮到要控制分頁的重複操作問題,還另外加了一個disable和enable的api,這個比較好理解了。當分頁被disable的時候,會顯示禁用的樣式,cursor為not-allowed,所有分頁操作都將無效。

實際上,我在最近的一個專案中, 寫類似demo的一個簡單分頁功能,就是這麼寫的,業務程式碼很少,邏輯也比較清晰,雖然說列表管理,比如渲染那一塊,還可以再封裝一下,但是在這種簡單場景中,不再去封裝,也是可以的,因為它本身已經很簡單,再想辦法封裝,也增加不了多少的靈活性。

現在還有不少的公司在採用沒有封裝的程式碼,分頁的功能在不同的頁面都寫一遍,每個位置都定義五六個function,比如goFirst goPrev goLast goNext goPage這種,從結果上來說沒啥不好,就是在做重複的事情的時候效率不高,不好維護。要是都能封裝起來,相信能給團隊帶來不少好處。

概要說明

先從option說起,以下是pageView.js定義的所有option及預設值:

我把其中需要再詳細解釋下的說明清楚。

1)pageIndexName和pageSizeName

這兩個用來定義分頁引數的名字,還記得那個getParams方法嗎,它是這樣的:

image

getParams返回一個物件,這個物件包含兩個鍵值對,鍵分別用pageIndexName和pageSizeName這兩個option,值就用分頁內部管理的分頁大小和頁碼。當外部呼叫這個方法時,就能直接把它的返回值作為查詢引數傳遞到後臺介面了。

2) middlePageItems,frontPageItems,endPageItems

也許看了demo裡面的分頁部分的效果就能明白它們三個的作用:

image

middlePageItems代表中間連續部分的分頁項的數量;

frontPageItems代表起始部分連續的分頁項的數量;

endPageItems代表結尾部分連續的分頁項的數量。

這三個option之所以要定義,是由當前這個分頁元件要做的效果,以及它使用的分頁演算法決定的。

然後pageView定義的例項方法就不過多說明了,因為都比較簡單,而且最核心的都已經在demo裡面體現出來,感興趣的話,照著用即可。如果對程式碼感興趣,碰到有疑問的,歡迎私信一起交流。

最後說下分頁演算法。影響分頁元件能不能通用的另外一個要素就是分頁演算法。有的可能不需要分頁演算法,直接從1到總頁數顯示出來就完了,但是這樣肯定有問題,尤其當總頁數很多的時候;有的分頁跟我這個就不太一樣,它可能只顯示當前頁在內的連續一部分頁碼,然後當切換不同的頁的時候,這個連續部分也不相同;我這裡用的是較為常見的一個演算法,首尾以及中間都有連續部分。詳細的渲染邏輯都在render方法裡面,但是最核心的東西其實還是getInterval這個函式:

它的作用在於返回中間連續部分的起止索引。根據這個起止索引渲染中間部分的頁碼,然後把start和frontPagetItems比較,渲染起始部分的頁碼;把end與與backPageItems比較,繪製結尾部分的頁碼。

其它問題

以上就算是這個分頁元件的全部核心內容了。但是最終來看,它還是有些問題的。一開始我就說過,這種東西要是能做到足夠靈活,能夠滿足不同專案裡面相同功能的話,這樣就才算強大。基於這點來看目前的pageView,它的問題在於:

1)固化了分頁演算法,要是換一個專案,產品不想搞這個分成首尾中間連續三部分的效果,那麼就必須改動原始碼才能適應需求了。要解決這個問題,可以考慮把pageView再抽象出一個父類,不同的子類去覆蓋render方法,也就是在專案中提供多個pageView的實現,要用哪個,根據需求來定。

2)沒有包括分頁大小,頁碼跳轉,記錄總數和記錄範圍這些內容,有可能其他專案需要這些東西,作為分頁的輔助功能。要解決這個問題,可以考慮在當前的版本上擴充,補充事件的監聽,新增一些合適的option,控制這些內容是否顯示即可。

我之所以沒有去解決上面的這些問題,有兩個原因:

1)就目前的所有場景來說,沒有碰到要額外內容的場景,如分頁大小等,所以先不處理,避免增加這個元件的複雜性;

2)對於分頁演算法,我認為在產品設計中沒有必要做出太多的不同的設計出來,所以固化一種沒有問題。因為不管從哪一方面,為不同的頁面提供不同的分頁演算法都是一件很划不來的事情,如果當產品出現這種問題的時候,我會盡力去把他說服。

當然,每個人想法不同,堅持自己的思想最好。

最後希望本文多少對大家有點用處,謝謝閱讀:)

相關文章