MUKI AI Summary
通常在網站上顯示大量資料,前端會從後端 API 獲取分頁資料,但若後端未提供分頁功能,可使用 Vue3 與 Element Plus 實現前端分頁。Element Plus 的 el-table
和 el-pagination
元件需自行處理。
利用工廠函式 (Factory Function) 可優化重複的分頁功能。工廠函式可接收參數並返回需要的資料,減少重複程式碼。透過工廠函式建立分頁狀態、處理資料過濾及跳頁功能,達到重用與減少冗餘程式碼的目的。...
需求與描述
通常要在網站上顯示大量的資料,會由後端提供 API,其中包含頁碼的參數與欄位,讓前端可以分頁打想要的資料。
但有時候,後端可能不會做分頁,而是把所有資料都丟給前端,如下圖所示,這個 api 的資料就多達 280 筆,在後端未提供分頁功能的情況下,我們可以怎麼處理呢?
在不用套件的情況下,我自己是用過 filter
函數去自製分頁功能,但做出來還是沒有用 Library 來的快速與美觀,有機會再跟大家分享我的原生寫法 XD。
使用 Element Plus 分頁處理前端資料
今天想跟大家介紹的是使用 Vue3 + Element Plus 製作分頁功能,不過容許我插播一下,假設你使用的是 React.js,那麼直接使用 Ant Design 的 Table 載入資料,他就會自動幫你完成分頁,不需要額外寫程式碼處理,超級方便 QwQ。
Element Plus 的話,我們要自行處理 el-table
以及 el-pagination
元件唷。
第一步:建立分頁資料
▼ 先定義好分頁的相關參數
<script> // 建立 100 筆假資料 const data = ref([]) for (let i = 0; i < 100; i++) { data.value.push({ name: `MUKI${i}`, age: i }) } const state = reactive({ page: 1, limit: 20, total: data.value.length }) </script>
第二步:加入表格與分頁元件
<template> <el-table :data="tableData()" style="width: 100%"> <el-table-column prop="name" label="姓名" width="80" /> <el-table-column prop="age" label="年齡" /> </el-table> <el-pagination background layout="prev, pager, next" :total="data.length" :page-size="20" @current-change="handleCurrentChange" /> </template>
第三步:處理串接的 data 資料
在第二步的程式碼,可以看到 <el-table>
的 data 資料是一個函式 tableData()
,我們要在這個函式裡面,搭配分頁與限制筆數,顯示實際的資料內容
<script> const tableData = () => { // 使用 filter 方法過濾 data.value 中的元素 return data.value.filter((item, index) => { // 只保留那些索引值在當前頁面範圍內的元素 return index >= (state.page - 1) * state.limit && index < state.page * state.limit }) } </script>
透過 filter
可以保留那些索引值(index
) 在當前頁面範圍內的元素,這樣就可以根據當下分頁的狀態取得對應的資料囉。
第四步:處理跳頁
Element Plus 的 Pagination 元件有一個 @current-change
事件,會在當前頁變動時觸發,我們要用這個事件讓表格顯示對應的頁面內容。
▼ 當 state.page
改變時,會影響 tableData()
函式 return
的資料,藉此修改表格內容
<script> const handleCurrentChange = (e) => { state.page = e } </script>
▼ 如此一來就做好分頁功能囉,前端收到的資料再多也不用怕了
用工廠函式 (Factory Function) 優化重複的分頁功能
在實際的專案裡,我們可能需要在多個地方使用分頁元件,這些分頁元件可能還需要處理不同的數據和狀態。例如,我們可能有兩個表格,每個表格都有自己的分頁狀態和數據過濾函數。這可能會導致我們的程式碼有重複和冗餘的情況。
▼ 像這些程式碼幾乎都要寫兩次以上
<template> <el-table :data="aLogData()"></el-table> <el-pagination :total="aLog.length" @current-change="handleCurrentAChange" /> <el-table :data="bLogData()"></el-table> <el-pagination :total="bLog.length" @current-change="handleCurrentBChange" /> </template> <script> const aState = reactive({ page: 1, limit: 20, total: aLog.value.length }) const bState = reactive({ page: 1, limit: 20, total: bLog.value.length }) const aLogData = () => { return aLog.value.filter((item, index) => { return index >= (aState.page - 1) * aState.limit && index < aState.page * aState.limit }) } const bLogData = () => { return bLog.value.filter((item, index) => { return index >= (bState.page - 1) * bState.limit && index < bState.page * bState.limit }) } const handleCurrentAChange = (val) => { aState.page = val } const handleCurrentBChange = (val) => { bState.page = val } </script>
明明是一模一樣的程式碼,卻因為資料來源不同,要寫很多一樣的程式碼,看起來非常的多餘。
因此我們可以使用工廠函式 (Factory Function) 來優化這部分的架構。
什麼是工廠函式 (Factory Function)
工廠函式是設計模式的一種,簡單來說,就是一個可重複使用的函示,他通常會接受一組參數,然後返回我們需要的資料。如果其中有一些複雜的邏輯或設定,也可以把他們寫在工廠函式裡,讓外部的呼叫更加簡潔。
優化重複的分頁功能
以這個功能為例子,我們可以用工廠函式來建立:
- 建立分頁狀態 (
state
) - 處理資料的過濾 (
tableData()
) - 跳頁 (
handleCurrentChange
)
建立分頁狀態
▼ 使用 createState()
工廠函式,將資料來源(raw data)當作參數傳入,並回傳 createState
對象
<script> const createState = (data) => reactive({ page: 1, limit: 20, total: data.value.length }) const aState = createState(aData) const bState = createState(bData) </script>
處理資料的過濾
▼ 將原本 tableData()
的函式,改成用工廠函式處理,傳入上個步驟取得的 aState
以及 aData
原始資料,過濾資料後並回傳
<script> const createData = (state, data) => () => { return data.value.filter((item, index) => { return index >= (state.page - 1) * state.limit && index < state.page * state.limit }) } const aLogData = createData(aState, aData) const bLogData = createData(bState, bData) </script>
▼ 原本的 <el-table>
資料來源也要修改
<template> <el-table :data="aLogData()"></el-table> <el-table :data="bLogData()"></el-table> </template>
跳頁
▼ handleCurrentChange()
的跳頁功能也需要優化為工廠函式,才知道現在是哪個資料需要跳頁
<script> const handleCurrentChange = (state) => (val: number) => { state.page = val } const handleCurrentAChange = handleCurrentChange(aState) const handleCurrentBChange = handleCurrentChange(bState) </script>
▼ 修改 <el-pagination>
的 @current-change
事件名稱
<template> <el-pagination :total="aData.length" @current-change="handleCurrentAChange" /> <el-pagination :total="bData.length" @current-change="handleCurrentBChange" /> </template>
在這個例子中,createState
、createData
和 handleCurrentChange
都是工廠函式,它們分別用於建立分頁狀態、處理資料過濾以及跳頁。我們使用這些函式幫不同的原始資料建立相應的狀態與函式,達到重用與減少多餘程式碼的需求
請問這樣子第一次等待後端 API 的資料時間是否很長,無法避免?
是的,這狀況無法避免!所以如果讀取的時間很長,還是希望能跟後端溝通分段給資料