Pagination - Express.js

  • 作成日:
  • 最終更新日:2025/10/11

ビュー

views/users/index.ejs

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="/stylesheets/style.css">
  <title>Document</title>
</head>
<body>
  <div id="header">
<h1>User Index</h1>
  </div>
  <div id="content">
<table>
    <tr>
      <th>ID</th>
      <th>Name</th>
      <th>Age</th>
    </tr>
    <% for(let i in users){ %>
      <% let obj = users[i]; %>
      <tr>
        <td><%= obj.id %></td>
        <td><%= obj.name %></td>
        <td><%= obj.age %></td>
      </tr>
    <% } %>
</table>
<ul id="pagination" class="clearfix">
  <% if(page > 1){ %>
  <li><a class="paging_item" href="/users/1" title="最初のページへ"><<</a></li>
  <% } else { %>
  <li><span class="paging_item"><<</span></li>
  <% } %>

  <% if(page > 1){ %>
  <li><a class="paging_item" href="/users/<%= prev %>" title="前のページへ"><</a></li>
  <% } else { %>
  <li><span class="paging_item"><</span></li>
  <% } %>

  <% if(page > 1){ %>
  <li><a class="paging_item" href="/users/1">1</a></li>
  <% } else { %>
  <li><span class="paging_item current">1</span></li>
  <% } %>

  <% if(start > pageRange){ %>
  <li><span>...</span></li>
  <% } %>

  <% for(let i in nums) { %>
    <% if(nums[i] == page){ %>
    <li><span class="paging_item current"><%= nums[i] %></span></li>
    <% } else { %>
    <li><a class="paging_item" href="/users/<%= nums[i] %>" class="num"><%= nums[i] %></a></li>
    <% } %>
  <% } %>

  <% if ((totalPage - 1) > end){ %>
  <li><span>...</span></li>
  <% } %>


  <% if(page < totalPage){ %>
  <li><a class="paging_item" href="/users/<%= totalPage %>"><%= totalPage %></a></li>
  <% } else if(totalPage == 1 || totalPage == 0) { %>
  <% } else { %>
  <li><span class="paging_item current"><%= totalPage %></span></li>
  <% } %>

  <% if(page < totalPage){ %>
  <li><a class="paging_item" href="/users/<%= next %>">></a></li>
  <% } else { %>
  <li><span class="paging_item">></span></li>
  <% } %>

  <% if(page < totalPage){ %>
  <li><a class="paging_item" href="/users/<%= totalPage %>">>></a></li>
  <% } else { %>
  <li><span class="paging_item">>></span></li>
  <% } %>
</ul>
  </div>
</body>
</html>

public/stylesheets/style.css

body {
  padding: 50px;
  font: "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
  color: #00B7FF;
}
.clearfix:after {
  content: "";
  clear: both;
  display: block;
}
#pagination li {
  list-style: none;
  float: left;
  margin-right: 20px;
  line-height: 24px;
}
#pagination li a {
  text-decoration: none;
}

自作ライブラリ

lib/pagination.js

module.exports = class Pagination {
  constructor(total){
this.view = 10; // 1ページに表示するレコード数
this.page_range = 2; // リンクを前後何ページ分表示するかの設定
this.count = total; // レコード数
this.total_page = Math.ceil(this.count / this.view); // ページ総数
this.current_page; // 現在のページ
this.sql_start = (this.current_page - 1) * this.view;
this.nums = []; // ページ番号格納用
  };

  notParam(){
this.current_page = 1;
this.sql_start = (this.current_page - 1) * this.view;

let prev = Math.max(this.current_page - 1, 1);
let next = Math.min(this.current_page + 1, this.total_page);

let start = Math.max(this.current_page - this.page_range, 2);
let end = Math.min(this.current_page + this.page_range, this.total_page - 1); // ページ番号終点
for (let i = start; i <= end; i++) { this.nums.push(i) }

let data = {
  view: this.view,
  sql_start: this.sql_start,
  total_count: this.count,
  prev: prev,
  next: next,
  start: start,
  end: end,
  nums: this.nums,
  page: this.current_page,
  pageRange: this.page_range,
  totalPage: this.total_page
}

return data;
  }

  param(param){
this.current_page = param;
this.sql_start = (this.current_page - 1) * this.view;

let prev = Math.max(this.current_page - 1, 1);
let next = Math.min(Number(this.current_page) + 1, this.total_page);

let start = Math.max(this.current_page - this.page_range, 2);
let end = Math.min(Number(this.current_page) + Number(this.page_range), this.total_page - 1); // ページ番号終点

for (let i = start; i <= end; i++) { this.nums.push(i) }

let data = {
  view: this.view,
  sql_start: this.sql_start,
  total_count: this.count,
  prev: prev,
  next: next,
  start: start,
  end: end,
  nums: this.nums,
  page: this.current_page,
  pageRange: this.page_range,
  totalPage: this.total_page
}

return data;
  }
}

ルーティング

app.js

var usersRouter = require('./routes/users');
app.use('/users', usersRouter);

routes/users.js

var express = require('express');
var router = express.Router();
const Users = require('../models/User');
const Pagination = require('../lib/pagination');

router.get('/', function(req, res, next) {
  new Promise((resolve)=>{
Users.countUser().then((total) => {
  let pagination = new Pagination(total);
  let data = pagination.notParam();
  
  Users.limitUser(data["sql_start"], data["view"]).then((results) => {
    data['users'] = results;
    data['msg'] = "";
    res.render('users/index', data);
  })
})
  })
});

router.get('/:page', function(req, res, next) {
  new Promise((resolve)=>{
Users.countUser().then((total) => {
  let pagination = new Pagination(total);
  let data = pagination.param(req.params.page);
  
  Users.limitUser(data["sql_start"], data["view"]).then((results) => {
    data['users'] = results;
    data['msg'] = "";
    res.render('users/index', data);
  })
})
  })
});

module.exports = router;

モデル

models/User.js

const mysql = require('mysql2/promise');
const pool = require('../db');

module.exports = {
  countUser: () => {
return new Promise ((resolve, reject) => {
  (async () => {
    try {
      const [results, fields] = await pool.query('SELECT COUNT(*) FROM users');
      resolve(results[0]["COUNT(*)"]);
    } catch (err) {
      console.log(err);
    }
  })();
});
  },
  limitUser: (sql_start, view) => {
return new Promise ((resolve, reject) => {
  (async () => {
    try {
      const [results, fields] = await pool.query('SELECT * FROM users  LIMIT ?, ?', [sql_start, view]);
      resolve(results);
    } catch (err) {
      console.log(err);
    }
  })();
});
  }
}

データベース設定

db.js

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  database: 'users',
  password: 'password',
});

module.exports = pool;

サンプルデータ投入用プログラム

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  database: 'users',
  password: 'password',
});

(async () => {
  try {
for(let i = 0; i < 200; i++){
  await pool.query('INSERT INTO users (name, age) VALUES (?, ?);', ["taro" + i, i] );
}
  } catch (err) {
console.log(err);
  }
  pool.end();
})();