一行代碼完成分頁(yè)模塊數(shù)據(jù)更新——Paging 快捷分頁(yè)模型

開(kāi)發(fā)移動(dòng)端頁(yè)面遇到大量的下拉刷新上拉加載模塊祟同?

每次都需要維護(hù)當(dāng)前頁(yè)數(shù)還有數(shù)據(jù)更新后的總頁(yè)數(shù)處理?

如果這些操作都可以用一行代碼實(shí)現(xiàn):

// 下拉刷新
pageViewModel.headerRefreshing();
// 上拉加載
pageViewModel.footerRefreshing();

感興趣的同學(xué)可以先戳這個(gè)鏈接先行體驗(yàn)一下效果,也可以戳這個(gè)鏈接看一下源代碼

接下來(lái)我們好好聊一聊怎么實(shí)現(xiàn)一行代碼完成分頁(yè)模塊

功能分解

1、首先我們需要思考的是分頁(yè)相關(guān)參數(shù)的處理

也就是 pageSize(單頁(yè)數(shù)目)currentPage(當(dāng)前頁(yè))totalPage(總頁(yè)數(shù))

我們需要一個(gè)實(shí)例來(lái)維護(hù)和更新這些參數(shù)

這里我設(shè)計(jì)了一個(gè) class

class PagingViewModel<T> {
    private currentPage: Ref<number>;
    private totalPage: Ref<number>;
    private pageSize: number;
   // 狀態(tài)變量
    refreshing: Ref<boolean>;
    loading: Ref<boolean>;
    finished: Ref<boolean>;

    constructor(opt: PagingOptions<T>) {
        this.pageSize = opt.pageSize ?? 20;
        this.currentPage = ref(1);
        this.totalPage = ref(1);
      
        this.refreshing = ref(false);
        this.loading = ref(false);
        this.finished = ref(false);
    }
}

使用 PagingViewModel 來(lái)管理這些參數(shù)轰驳,在觸發(fā)刷新和加載行為之后實(shí)時(shí)更新,并且通過(guò) 3 個(gè)狀態(tài)變量(刷新中弟灼、加載中级解、已全部加載)來(lái)標(biāo)識(shí)此時(shí)的 Paging 加載狀態(tài)

2、其次我們需要考慮數(shù)據(jù)的來(lái)源與更新

這里主要是體現(xiàn)在通過(guò)接口獲取數(shù)據(jù)這一塊

也就是 params(請(qǐng)求參數(shù))田绑、requestFn(請(qǐng)求體)勤哗、datas(用于渲染的數(shù)據(jù)源)

這里我們?cè)賹⑦@些內(nèi)容合并進(jìn)上面的 class 中

class PagingViewModel<T> {
    private currentPage: Ref<number>;
    private totalPage: Ref<number>;
    private pageSize: number;
    // 新增屬性
    private params: any;
    private datas: Ref<Array<T>>;
    private requestFn: (params: any) => Promise<any>;
    private responseCompletion?: (vm: PagingViewModel<T>, datas: Array<any>) => Array<any>;

    refreshing: Ref<boolean>;
    loading: Ref<boolean>;
    finished: Ref<boolean>;

    constructor(opt: PagingOptions<T>) {
        this.requestFn = opt.requestFn;
        this.params = opt.params || {};
        this.datas = opt.datas;
        this.pageSize = opt.pageSize ?? 20;

        this.currentPage = ref(1);
        this.totalPage = ref(1);
        this.refreshing = ref(false);
        this.loading = ref(false);
        this.finished = ref(false);
    }
}

現(xiàn)在我們的 class 已經(jīng)初具雛形,可以為其增加行為 loadData()

/**
 * 加載數(shù)據(jù)
 */
loadData() {
    // 組合基本的請(qǐng)求參數(shù)
    const params = {
        currentPage: this.currentPage.value,
        pageSize: this.pageSize,
        ...this.params,
    };
   // 刷新時(shí)清空數(shù)據(jù)源
    if (this.currentPage.value === 1) {
        this.datas.value = [] as Array<T>;
    }
   // 網(wǎng)絡(luò)請(qǐng)求主體
    this.requestFn(params).then((response) => {
        if (!response) {
            return;
        }
        // 記錄總頁(yè)數(shù)
        this.totalPage.value = response.totalPage;
        let resDatas = response.responseObject.items;
        if (this.responseCompletion) {
            // 需要特殊處理的數(shù)據(jù)源由該 hook 完成
            resDatas = this.responseCompletion(this, response.datas);
        }
        // 處理第一頁(yè)和其他頁(yè)數(shù)據(jù)組合
        if (this.currentPage.value === 1) {
            this.datas.value = resDatas;
        } else {
            this.datas.value = this.datas.value.concat(resDatas);
        }
        // 加載結(jié)束掩驱,更新?tīng)顟B(tài)
        this.didLoaded();
    });
}
/**
 * 加載結(jié)束芒划,狀態(tài)更新
 */
didLoaded() {
    // 處理第一頁(yè)和其他頁(yè)的狀態(tài)
    if (this.currentPage.value === 1) {
        this.refreshing.value = false;
        this.finished.value = false;
    } else {
        this.loading.value = false;
    }
}

這里可能有小伙伴就有疑問(wèn)了,如果我需要對(duì)網(wǎng)絡(luò)請(qǐng)求拿到的數(shù)據(jù)源進(jìn)行處理后才提供給界面渲染怎么辦欧穴?

那我們就增加一個(gè)Hook (responseCompletion)來(lái)處理接口數(shù)據(jù)

剩下就是處理 currentPage 為 1 的情況和不為 1 的情況了

3民逼、最后實(shí)現(xiàn)上拉加載和下拉刷新

/**
 * 下拉刷新
 */
headerRefreshing() {
    // 重置當(dāng)前頁(yè)并刷新數(shù)據(jù)
    this.currentPage.value = 1;
    this.loadData();
}
/**
 * 上拉加載
 */
footerRefreshing() {
    // 這里根據(jù) totalPage 控制顯示沒(méi)有更多數(shù)據(jù)
    if (this.currentPage.value === this.totalPage.value) {
        this.finished.value = true;
        this.didLoaded();
        return;
    }
    // 當(dāng)前頁(yè)自增并請(qǐng)求下一頁(yè)數(shù)據(jù)
    this.currentPage.value += 1;
    this.loadData();
}

到此,我們的 PagingViewModel 已經(jīng)可以正常工作啦~

這里提供一下最基礎(chǔ)的調(diào)用方式

// 網(wǎng)絡(luò)請(qǐng)求
const requestFn = (params: any) => {
    return new Promise<any>((resolve) => {
        // 這里模擬請(qǐng)求數(shù)據(jù)
        const response = mockDatas(params.currentPage, params.pageSize);
        resolve(response);
    });
}
// 渲染數(shù)據(jù)源
const datas = ref<ResponseObject[]>([]);
// 分頁(yè)vm
const pageViewModel = new PagingViewModel<any>({
    requestFn,
    datas,
    pageSize: 5,
});
// 刷新數(shù)據(jù)
pageViewModel.headerRefreshing();
// 加載數(shù)據(jù)
pageViewModel.footerRefreshing();

總結(jié)

這里想和大家分享的只是構(gòu)建快捷分頁(yè)模型的一個(gè)思路涮帘,具體細(xì)節(jié)的雕琢還需要深入思考

很多分頁(yè)參數(shù)的命名定義可能會(huì)有所不同拼苍,返回值的數(shù)據(jù)結(jié)構(gòu)也會(huì)有所不同

所以,大家領(lǐng)悟思路就好调缨,可以根據(jù)這個(gè)思路做一套適合自己業(yè)務(wù)的分頁(yè)模型

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疮鲫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子弦叶,更是在濱河造成了極大的恐慌俊犯,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件湾蔓,死亡現(xiàn)場(chǎng)離奇詭異瘫析,居然都是意外死亡砌梆,警方通過(guò)查閱死者的電腦和手機(jī)默责,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)贬循,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人桃序,你說(shuō)我怎么就攤上這事杖虾。” “怎么了媒熊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵奇适,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我芦鳍,道長(zhǎng)嚷往,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任柠衅,我火速辦了婚禮皮仁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘菲宴。我一直安慰自己贷祈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布喝峦。 她就那樣靜靜地躺著势誊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谣蠢。 梳的紋絲不亂的頭發(fā)上粟耻,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音漩怎,去河邊找鬼勋颖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛勋锤,可吹牛的內(nèi)容都是我干的饭玲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼叁执,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼茄厘!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起谈宛,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤次哈,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后吆录,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體窑滞,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哀卫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巨坊。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖此改,靈堂內(nèi)的尸體忽然破棺而出趾撵,到底是詐尸還是另有隱情,我是刑警寧澤共啃,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布占调,位于F島的核電站,受9級(jí)特大地震影響移剪,放射性物質(zhì)發(fā)生泄漏究珊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一纵苛、第九天 我趴在偏房一處隱蔽的房頂上張望苦银。 院中可真熱鬧,春花似錦赶站、人聲如沸幔虏。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)想括。三九已至,卻和暖如春烙博,著一層夾襖步出監(jiān)牢的瞬間瑟蜈,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工渣窜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铺根,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓乔宿,卻偏偏與公主長(zhǎng)得像位迂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子详瑞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359