728x90
반응형
게시글 목록을 가져오는 라우트는 '/articles' 경로에 설정되어 있습니다. 클라이언트는 페이지 번호를 쿼리 매개변수로 전달할 수 있습니다.
먼저 server.js 에 가서 게시판 목록 불러오는 부분 코드를 수정합니다.
// server.js
// 게시판에서 게시판 목록을 가져오는 라우트입니다.
app.get('/articles', (req, res) => {
const page = parseInt(req.query.page) || 1; // 요청된 페이지 번호를 쿼리 매개변수에서 가져옵니다
const pageSize = 3; // 이 값을 원하는 대로 조절하세요
// 요청된 페이지 및 페이지 크기를 기반으로 레코드를 건너뛰기 위한 오프셋을 계산합니다.
const offset = (page - 1) * pageSize;
// 'board' 테이블에서 페이지별로 정렬된 레코드를 선택하는 데이터베이스 쿼리를 실행합니다.
const query = 'SELECT * FROM board ORDER BY idx DESC LIMIT ? OFFSET ?';
connection.query(query, [pageSize, offset], (err, rows) => {
if (err) {
console.error('페이징된 게시글 목록을 가져오는 중 오류 발생:', err);
// 오류가 발생하면 오류 응답을 전송합니다.
return res.status(500).send('서버 오류');
}
// 'board' 테이블의 총 레코드 수를 가져오는 쿼리
const countQuery = 'SELECT COUNT(*) AS totalCount FROM board';
connection.query(countQuery, (err, result) => {
if (err) {
console.error('총 레코드 수를 가져오는 중 오류 발생:', err);
return res.status(500).send('서버 오류');
}
const totalCount = result[0].totalCount;
const totalPages = Math.ceil(totalCount / pageSize);
// 검색된 레코드 및 최대 페이지 수를 응답으로 전송합니다.
res.send({ rows, totalPages, page_current: page, page_max: totalPages });
});
});
});
코드 동작 설명
- 클라이언트는 '/articles' 경로로 GET 요청을 보내며, 페이지 번호를 쿼리 매개변수로 전달합니다.
- 요청된 페이지 및 페이지 크기를 기반으로 MySQL 쿼리를 통해 해당 페이지의 게시글을 가져옵니다.
- 동시에 'board' 테이블의 전체 레코드 수를 가져와 전체 페이지 수를 계산합니다.
- 검색된 게시글 목록과 페이지 정보를 응답으로 클라이언트에게 전송합니다.
그다음 페이징 처리 기능을 HTML에 추가하기 위해 index.html에 가서 아래 코드를 추가합니다.
<!-- index.html -->
<body>
<!-- 페이지의 제목을 설정합니다. -->
<title>게시글 목록</title>
<!-- 페이지 상단에 표시되는 제목입니다. -->
<h1>게시글 목록</h1>
<!-- 네비게이션 링크 -->
<nav>
<ul>
<!-- 게시글 작성 페이지로 이동하는 링크 -->
<li><a href="create.html">게시글 작성</a></li>
</ul>
</nav>
<!-- 게시글 목록을 표시하는 부분입니다. -->
<ul id="articles-list"></ul>
<!-- Pagination controls -->
<div id="pagination" class="col-8">
<ul class="pagination pagination-sm justify-content-center align-items-center h-100 mb-0" id="pageList"></ul>
</div>
스크립트 기능도 추가해줍니다.
// 변수 초기화
const articlesList = document.getElementById('articles-list'); // HTML에서 게시글 목록을 표시할 엘리먼트
const pageListElement = document.getElementById('pageList'); // HTML에서 페이지 목록을 표시할 엘리먼트
let currentPage = 1; // 현재 페이지 변수 초기화
let maxPages = 1; // 최대 페이지 수를 저장하는 변수 초기화
// 함수: 게시글 목록을 가져오는 함수
function fetchArticles(page) {
const pageSize = 5; // 페이지당 표시할 게시글 수 (원하는 값으로 조절)
const startIndex = (page - 1) * pageSize; // 가져올 게시글의 시작 인덱스
// 서버로부터 게시글 데이터 가져오기
fetch(`http://localhost:3000/articles?page=${page}`)
.then(response => response.json())
.then(data => {
const articles = data.rows; // 서버에서 받아온 게시글 데이터
articlesList.innerHTML = ''; // 이전에 표시된 게시글 초기화
// 각 게시글을 리스트에 추가
articles.forEach(article => {
const li = document.createElement('li');
li.innerHTML = `
<strong>Title:</strong> ${article.title}<br>
<strong>Writer:</strong> ${article.writer}<br>
<strong>Content:</strong> ${article.content}<br>
<strong>Views:</strong> ${article.view_cnt}<br>
<strong>Insert Time:</strong> ${article.insert_time}<br>
<strong>Update Time:</strong> ${article.update_time ? article.update_time : 'N/A'}<br>
<strong>Delete Time:</strong> ${article.delete_time ? article.delete_time : 'N/A'}<br>
<a href="article-details.html?id=${article.idx}">상세 정보 보기</a><br>
<hr>
`;
articlesList.appendChild(li);
});
// 전체 페이지 수 업데이트
maxPages = data.totalPages;
// 페이지 목록 업데이트
renderPaginationControls(data.page_current, data.page_max);
});
}
// 함수: 페이지 변경 이벤트 처리
function changePage(page) {
// 페이지가 1보다 작아지지 않도록 보장
currentPage = Math.max(page, 1);
// 페이지가 최대 페이지 수를 초과하지 않도록 보장
currentPage = Math.min(currentPage, maxPages);
// 페이지를 업데이트하고 게시글을 가져옵니다.
fetchArticles(currentPage);
}
// 함수: 페이지 목록 렌더링
function renderPaginationControls(page_current, page_max) {
// 페이지 목록 엘리먼트를 찾지 못한 경우 에러를 방지하기 위해 확인
if (!pageListElement) {
console.error("Error in renderPaginationControls: Unable to find the 'pageList' element on the page.");
return;
}
// 이전 페이지 목록 초기화
pageListElement.innerHTML = '';
const offset = 2;
const previousBtnEnabled = page_current > 1; // 이전 버튼 활성화 여부
const nextBtnEnabled = page_current < page_max; // 다음 버튼 활성화 여부
// "이전" 버튼 추가
pageListElement.innerHTML += `
<li class="page-item ${previousBtnEnabled ? '' : 'disabled'}">
<a class="page-link" href="#" onclick="changePage(${page_current - 1})" ${previousBtnEnabled ? '' : 'tabindex=-1'}>«</a>
</li>
`;
// 페이지 번호 추가
for (let i = 1; i <= page_max; i++) {
if (i == 1 || i == page_max || (i >= page_current - offset && i <= page_current + offset)) {
pageListElement.innerHTML += `
<li class="page-item ${page_current == i ? 'active' : ''}">
<a class="page-link" href="#" onclick="changePage(${i})">${i}</a>
</li>
`;
} else if (i == 2 || i == page_max - 1) {
pageListElement.innerHTML += `
<li><a class="page-link">...</a></li>
`;
}
}
// "다음" 버튼 추가
pageListElement.innerHTML += `
<li class="page-item ${nextBtnEnabled ? '' : 'disabled'}">
<a class="page-link" href="#" onclick="changePage(${page_current + 1})" ${nextBtnEnabled ? '' : 'tabindex=-1'}>»</a>
</li>
`;
}
// 초기 페이지 로딩 시 첫 번째 페이지의 게시글 가져오기
fetchArticles(1);
코드 동작 설명
1. 코드 초기화
먼저, 필요한 변수들을 초기화합니다.
// 변수 초기화
const articlesList = document.getElementById('articles-list'); // HTML에서 게시글 목록을 표시할 엘리먼트
const pageListElement = document.getElementById('pageList'); // HTML에서 페이지 목록을 표시할 엘리먼트
let currentPage = 1; // 현재 페이지 변수 초기화
let maxPages = 1; // 최대 페이지 수를 저장하는 변수 초기화
2. 함수: 게시글 목록 가져오기
게시글을 가져와 HTML 엘리먼트에 동적으로 추가하는 함수입니다.
// 함수: 게시글 목록을 가져오는 함수
function fetchArticles(page) {
const pageSize = 5; // 페이지당 표시할 게시글 수 (원하는 값으로 조절)
const startIndex = (page - 1) * pageSize; // 가져올 게시글의 시작 인덱스
// 서버로부터 게시글 데이터 가져오기
fetch(`http://localhost:3000/articles?page=${page}`)
.then(response => response.json())
.then(data => {
const articles = data.rows; // 서버에서 받아온 게시글 데이터
articlesList.innerHTML = ''; // 이전에 표시된 게시글 초기화
// 각 게시글을 리스트에 추가
articles.forEach(article => {
const li = document.createElement('li');
li.innerHTML = `
<!-- 게시글 내용 추가 -->
<a href="article-details.html?id=${article.idx}">상세 정보 보기</a><br>
<hr>
`;
articlesList.appendChild(li);
});
// 전체 페이지 수 업데이트
maxPages = data.totalPages;
// 페이지 목록 업데이트
renderPaginationControls(data.page_current, data.page_max);
});
}
3. 함수: 페이지 변경 이벤트 처리
페이지 변경 버튼을 클릭했을 때 호출되는 함수입니다.
// 함수: 페이지 변경 이벤트 처리
function changePage(page) {
// 페이지가 1보다 작아지지 않도록 보장
currentPage = Math.max(page, 1);
// 페이지가 최대 페이지 수를 초과하지 않도록 보장
currentPage = Math.min(currentPage, maxPages);
// 페이지를 업데이트하고 게시글을 가져옵니다.
fetchArticles(currentPage);
}
4. 함수: 페이지 목록 렌더링
페이지 목록을 동적으로 생성하여 페이징 컨트롤을 표시하는 함수입니다.
// 함수: 페이지 목록 렌더링
function renderPaginationControls(page_current, page_max) {
// 페이지 목록 엘리먼트를 찾지 못한 경우 에러를 방지하기 위해 확인
if (!pageListElement) {
console.error("Error in renderPaginationControls: Unable to find the 'pageList' element on the page.");
return;
}
// 이전 페이지 목록 초기화
pageListElement.innerHTML = '';
// ... (생략)
// "이전" 버튼 추가
pageListElement.innerHTML += `
<!-- 이전 버튼 추가 -->
`;
// 페이지 번호 추가
for (let i = 1; i <= page_max; i++) {
// ... (생략)
}
// "다음" 버튼 추가
pageListElement.innerHTML += `
<!-- 다음 버튼 추가 -->
`;
}
5. 초기 페이지 로딩
페이지가 처음 로딩될 때 초기 게시글을 가져오는 함수를 호출합니다.
// 초기 페이지 로딩 시 첫 번째 페이지의 게시글 가져오기
fetchArticles(1);
이제 페이징 기능을 보기 좋게 css코드를 추가시켜 줍니다.
/* 페이징 컨트롤의 스타일을 설정합니다. */
.pagination {
display: inline-block;
margin-top: 20px;
}
.pagination li {
display: inline;
margin-right: 5px;
}
.pagination a {
color: #007bff;
padding: 5px 10px;
text-decoration: none;
border: 1px solid #007bff;
border-radius: 3px;
}
.pagination .active a {
background-color: #007bff;
color: #fff;
}
.pagination a:hover {
background-color: #0056b3;
color: #fff;
}
.pagination .disabled a {
pointer-events: none;
cursor: not-allowed;
background-color: #ccc;
color: #777;
}
실행 화면
전체코드는 깃허브에 올려두겠습니다.
https://github.com/phs1579/NodeBoard 를 참조해주세요.
728x90
반응형
'Node.js > Node 프로젝트 예제' 카테고리의 다른 글
[Node.js] 게시판[4/4] 댓글 기능, 이미지 업로드 (1) | 2023.12.27 |
---|---|
[Node.js] 게시판[3/4] 회원가입, 로그인 추가하기 (1) | 2023.12.26 |
[Node.js] 게시판(1/4) CRUD 만들기, 게시글 작성/상세/수정/삭제 (1) | 2023.12.20 |
node.js 웹 채팅 (1) | 2023.12.19 |