從Toast到Pagination: 如何優雅地寫組件

做者:孫輝,美團金融前端團隊成員。15年畢業加入美團,相信技術,更相信技術只是大千世界裏知識的一種,我的博客: sunyuhui.comhtml

最近在作的新業務(PC端)裏面,本身寫了幾個組件,既有簡單的toast,也有稍微複雜一點的pagination(分頁),在這裏記錄下本身的思考過程,但願對你們有幫助 ~前端

Toast

實現基本功能

toast你們已經很熟悉了,其應用場景是:完成某個操做後,給用戶一個提示,必定時間後消失jquery

基於這個思路,咱們很快能實現出一個基於jQuery能用第一版toastgit

其中關鍵的代碼只有幾行:github

var elementContent = '<div class="toast-container" style="' + style + '"> <span class="toast-content"> ' + options.content + ' </span> </div>';
$('body').append(elementContent);
//必定時間後消失
var timeout = setTimeout(function() {
    $('.toast-container').remove();
}, options.time*1000);複製代碼
使用優化

上面的toast已經能夠用了,可是我在用的時候,發現有一點不方便,由於我每次調用的時候都須要傳入一個object對象,即使我就想用默認的樣式,默認的消失時間。那我能不能就傳入一個我想要給用戶展現的字符串呢?ajax

簡單改造一下:bash

...
//參數爲字符串時,將其做爲content屬性值
if(Object.prototype.toString.call(options) === '[object String]') {
    options = $.extend(defaultParam, {
        content: options
    });
} else if(Object.prototype.toString.call(options) === '[object Object]') {
        options = $.extend(defaultParam, options);
} else {
        console.error('only support String or Object for param');
        return;
}
...複製代碼

沒有花費太多心思,咱們就能讓使用方式變得更加簡單,有了支持多參數形式的toast架構

去掉第三方依賴

咱們在實現toast時使用了jQuery這個第三方庫,不得不說,我有時候真心以爲jQuery讓前端門檻下降了很多,可是,業務技術架構並非一成不變的,有的項目裏並不會使用jQuery。那麼咱們就須要提供一個不依賴第三方庫toastapp

只須要將上面用到jQuery的地方使用原生JS實現就好了,其中有個深拷貝函數$.extend你們須要關注,在這裏咱們就不細說了。函數

完整代碼:原生JavaScript實現的toast

到這裏咱們就實現了一個功能比較完整的toast,整個代碼很簡單,但我重點想說的是不斷優化的過程:

  • 第一個版本,咱們的要求是:能用
  • 第二個版本,咱們的要求是:用起來方便
  • 第三個版本,咱們的要求是:不依賴第三方庫,能適應不一樣技術架構

Pagination

咱們經過寫toast組件的過程,已經瞭解瞭如何寫好一個組件,如今咱們將這個思路應用到一個稍微有點複雜的組件上:分頁組件。

分頁組件一般是和表格一塊兒用的,使用場景是:將比較大的數據量分頁,每頁展現固定條數的數據,用戶能夠經過分頁組件自由選擇查看任何頁碼的數據,咱們梳理下思路,分爲這麼幾步:

  1. 經過當前頁碼總頁數展現出頁碼選擇器
  2. 給每一頁綁定點擊事件,點擊時獲取數據,而且更新頁碼選擇器

其中有個詞是:頁碼選擇器,其實指的就是這個東西:

頁碼選項
頁碼選項

如何展現出頁碼選擇器?,我發現有篇博客講解的思路很是好:如何寫一個簡單的分頁,可是在代碼細節上,對於不熟悉分頁的人不太好理解,我沿用這個思路,具體細節上有修改。

整體思路就是以當前頁碼爲分割點,分別獲得以前和以後的頁碼。

如今咱們用代碼第一版pagination組件實現這個效果(忽略CSS),獲得上圖中的頁碼選擇器,其中關鍵代碼以下,我作了詳細註釋:

/**
 * [getPage 獲取頁碼展現]
 * @param  {[type]} currentPage [當前頁碼]
 * @param  {[type]} totalPage  [頁碼總數]
 * @return {[type]}             [description]
 */
function getPage(currentPage, totalPage) {
    //顯示:第一頁,當前頁,當前頁的先後兩頁,最後一頁
    //以當前頁爲分割點,分別獲得當前頁前面的頁碼和後面的頁碼
    var pageStr = '<a class="active">' + currentPage + '</a>';
    // 將當前頁先後2頁的頁碼展現出來
    for(var i = 1; i<=2; i++) {
        //獲得當前頁前兩頁的的頁碼
        //其中的1指第一頁
        if(currentPage > i+1) {
            pageStr = '<a>' + (currentPage - i) + '</a>' + pageStr;
        }
        //獲得當前頁後兩頁的頁碼
        if(currentPage+i < totalPage) {
            pageStr = pageStr + '<a>' + (currentPage + i) + '</a>';
        }
    }
    //獲得當前頁前面用...表示的頁碼
    //兩個1分別表示第一頁,和當前頁
    if( currentPage > 2+1+1 ) {
        pageStr = ' ... ' + pageStr;
    }

    //獲得上一頁
    if(currentPage > 1) {
        pageStr = '<a class="prePage">上一頁</a><a>1</a>' + pageStr;
    }

    //獲得當前頁後面用...表示的頁碼
    //其中1表示最後一頁,當前頁已經在前面計算過,這裏再也不計算
    if( currentPage+2+1 < totalPage ) {
        pageStr = pageStr + ' ... ';
    }

    //獲得下一頁
    if( currentPage < totalPage ) {
        pageStr = pageStr + '<a>' + totalPage + '</a><a class="lastPage">下一頁</a>';
    }

    return pageStr;
}複製代碼

最終咱們達到的效果是這樣的:

分頁效果圖
分頁效果圖

其中.pagination-container這個元素是整個分頁組件的容器,直接在html頁面中定義就行。

在上面的效果圖中,咱們點擊不一樣的頁碼只是【跳轉到了不一樣的頁面】,但在實際項目中,咱們一般都是獲取要獲取數據,更新表格。

咱們把bindEvent函數稍微更新一下

var $this = $(this);
var pageNum;
var currentPage = +$('.pagination-list a.active').text();
if( $this.hasClass('prePage') ) {
    //點擊【上一頁】
    pageNum = currentPage - 1;
} else if( $this.hasClass('lastPage') ) {
    //點擊【下一頁】
    pageNum = currentPage + 1;
} else {
        pageNum = +$this.text();
}
//獲取表格數據
//執行ajax以前的回調函數,好比加個loading
options.beforeCallback && options.beforeCallback();
$.ajax({
    url:options.url,
    type: options.type,
    data: options.data
}).done(function(res){
    //執行ajax以後的回調函數,好比隱藏loading
    options.afterCallback && options.afterCallback();
    //請求成功後的回調函數
    options.callback && options.callback(res);
    // 更新頁碼
    var pageHtml = getPage(pageNum, options.totalPage);
    $('.pagination-list').html(pageHtml);
}).fail(function(error){
    //執行ajax以後的回調函數,好比隱藏loading
    options.afterCallback && options.afterCallback();
    alert('請求出錯,請重試');
});複製代碼

這樣咱們就完成了一個比較完整的分頁組件

去掉第三方依賴

在這個組件裏去掉依賴就是去掉對jQuery的依賴,咱們只須要把使用jquery方法的地方用原生JavaScript實現一遍就行。總結一下,咱們須要本身實現深拷貝函數事件代理函數發送Ajax。完整代碼:原生JavaScript實現的分頁組件

你們能夠對比一下,去掉了jQuery以後,咱們多寫了多少代碼啊。其中有不少細節須要考量,因此我一直以爲寫原生JavaScript才能真正考察一個前端的功底。

總結

ok, 到這裏就差很少了,本文重點不在於告訴你們如何去實現某一個具體的組件(畢竟咱們只涉及到兩個組件),而在於闡述一種觀點:咱們寫的組件即使只是用在咱們本身的業務中,也不要知足於能用就行,一步步優化組件,優化功能,能適應不一樣技術場景,不只能提高技術能力,還能讓咱們意識到而且實踐如何把一件事從60分作到90分

最後,團隊爲了招聘方便,整了個公衆號,主要是一些招聘信息,團隊信息,全部的技術文章在公衆號裏也能夠看到,對了,若是你想去美團其餘團隊,咱們也能夠幫你內推哦 ~

二維碼
二維碼

參考:

如何寫一個簡單的分頁

相關文章
相關標籤/搜索