Pagination 分頁實作

前言

紀錄學習分頁的實作邏輯,將大量需要呈現的資訊分隔開來,避免造成瀏覽問題。

邏輯

在製作分頁的時候會需要使用到幾個要點,限制每頁需要的資料,在前往下一頁的時候需要使用偏移。

  • limit: 限制資訊筆數
  • offset: 偏移量
  • page: 目前頁數
  • pages: 全部數到的頁數
  • totalPage: 將 pages 轉換成頁碼 array 方便前端渲染
  • previous: 往前一頁
  • next: 往後移頁

搭配 sequelize 提供的語法 offset、limit 來完成目的

// Fetch 10 instances/rows
Project.findAll({ limit: 10 });

// Skip 8 instances/rows
Project.findAll({ offset: 8 });

// Skip 5 instances and fetch the 5 after that
Project.findAll({ offset: 5, limit: 5 });

步驟

  1. 設定讀取筆數
  2. 宣告頁碼
  3. 宣告 offset 計算偏移量
  4. 計算總頁數(無條件進位) = 總資料數 / 讀取筆數
  5. 使用 array 寫進數量
  6. 使用判斷式,計算前一頁頁數
  7. 使用判斷式,計算下一頁頁數

實作

最初:

// 設定讀取筆數
let pagaLimit = 10
// 宣告頁碼
let page = Number(req.query.page) || 1
// 宣告 offset 計算偏移量
let offset = 0
if (req.query.page) {
offset = (req.query.page - 1) * pageLimit
}
Project.findAndCountAll({offest: offset, limit: pagaLimit})
.then(projects => {
// 計算總頁數
let pages = Math.ceil( projects.count / pageLimit )
// 產生 array
let totalPage = Array.from({length: pages}).map((item, index) => index + 1)
// 前一頁
let prev = page - 1 < 1 ? 1 : page -1
// 後一頁
let next = page + 1 > pages ? pages : page + 1
return res.render('path', {projects, page, totalPage, prev, next})
})

第二次實作:
最後需要傳出 page、 totalPage、 prev、next,一樣會使用到 pagaLimit、page、offse、totalPage、prev、next。

// 從其他地方傳入筆數
let pagaLimit = 10
const middleware = {
// refactor 程式碼,先取得 page,跟要傳入資料庫的條件limiting。
pageInfo: (pageLimit, pageNumber = 1) => { // pageNumber 預設 1
const page = parseInt(pageNumber) // 轉型字串
const limiting = { offset: pageLimit * (page - 1), limit: pageLimit}
},

// refactor 取得 totalPage,在找出資料後傳入,1.資料筆數、2.限制筆數、3.當前頁數
getPagination: (count, pageLimit, page) => {
let pages = Math.ceil(count / pageLimit) // 筆數 / 限制筆數取得總頁數
// 製作成 array 使用到 pages。
let totalPage = Array.from({ length: pages }, (item, index) => index + 1)
// 前頁
let prev = page - 1 < 1 ? 1 : page - 1
// 下頁
let next = page + 1 > pages ? pages : page + 1
return {totalPage, prev, next}
}
}

// 使用的地方
// require middleware
const controller = {
getInformation: async (req, res) => {
try {
const { page, limiting } = await pageInfo(pageLimit, req.query.page)
const projects = await Project.findAndCountAll(limiting)
const {totalPage, prev, next} = await getPagination(projects.count, pageLimit, page)
return res.render('path', {projects, page, totalPage, prev, next})
} catch (error) {
console.log(error)
}
}
}

心得

將目前學習到的分頁方式做個小整理,在未來希望能夠了解更多不同的做法。