Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- html 코드
- 자바스크립트
- 자바스크립트 프로미스
- 자바스크립트 scope
- javascript opreators
- 자바스크립트 반복문
- javascript opreator
- html 주석
- 자바스크립트 실행 컨텍스트
- 자바스크립트 클래스
- css position
- HTML
- css3
- javascript closure
- 티스토리챌린지
- 웹 개발 트렌드
- 자바스크립트 async await
- 자바스크립트 연산자
- 자바스크립트 생성자 함수
- 프론트엔드 리액트
- 자바스크립트 상속
- css 포지션
- 리액트 개념
- 자바스크립트 클로저
- 자바스크립트 promise
- 오블완
- 프론트엔드
- javascript
- 자바스크립트 스코프
- CSS
Archives
- Today
- Total
Multi Developer SuHo
[자바스크립트 실습] 자바스크립트로 페이지네이션(PageNation) 구현하기 본문
SMALL
안녕하세요~ 오늘은 자바스크립트로 페이지네이션(PageNation)을 구현해보겠습니다.
📑목차
1. 페이지네이션(PageNation)
1-1. 페이지네이션이란?
1-2. 페이지네이션 구조
1-3. 페이지네이션 실습 코드
서론
본론으로 들어가기 앞서 혹시 페이지네이션이라고 들어보신 적 있으신가요? 아니면 페이지네이션 화면을 보셨던 적이 있으실까요? "페이지네이션" 키워드만 들었을 때는 와닿지 않을 수 있습니다.
그럼 웹 사이트 마다 이런 화면을 보신적 있으신가요?
이 화면은 저의 티스토리에서 캡쳐한 화면입니다. 이런 화면으로 다음 페이지에 대한 내용이 나타나도록 나눠서 구현한 것이 페이지네이션(PageNation)입니다. 그럼 이러한 기능을 구현하기 위해 본론으로 넘어가볼까요?
본론
1-2. 페이지네이션 구조
페이지네이션 기능을 구현하기 전 페이지네이션에 대한 구조를 먼저 보셔야 합니다.
간단한 예를 들면, 게시글 100개가 있을 때 이를 10개씩 나누어 10개의 페이지로 나누고, 각 페이지에서 10개씩만 보여주다는 구조를 먼저 생각하고 로직을 작성해야합니다.
#### 페이지네이션
> 페이지의 총 갯수에서 보여줘야할 페이지의 갯수를 나누면 페이지네이션의 넘버의 갯수가 나온다.
> 소수점 단위는 올림처리를 해서 페이지의 넘버를 생성
### 공식
- 시작 인덱스 = (현재 페이지 넘버 - 1) X 페이지당 보여줄 갯수
예 ) 1번 페이지 넘버의 화면을 보고 있고 글의 갯수는 5개
(1-1) X 5 === 0(인덱스)번 글부터 시작된다. 첫번째 페이지
(2-1) X 5 === 5(인덱스)번 글부터 시작된다. 두번째 페이지
- 끝 인덱스 = 시작 인덱스 + 페이지의 아이템 갯수
- 전체 페이지의 갯수를 계산
총 페이지 = (전체 글 갯수 + 보여줄 글의 갯수 - 1) / 보여줄 페이지의 갯수
### 슬라이딩 페이지네이션
- 1 2 3 4 5 >
- < 6 7 8 9 10 >
- < 11 12 13 14 15 >
> (2 - 1) / 5 === 0.xxx ==== 0 번의 그룹
> (6 - 1) / 5 === 1 1번의 그룹
> (11 - 1) / 5 === 2 2번의 그룹
> 현재 그룹은 (보고있는 그룹 - 1) / 그룹의 크기 = 현재 그룹
- 시작 페이지 = 현재 그룹 X 그룹의 크기 + 1
> (8 - 1) / 5 === 1번 그룹
> 1번 그룹의 첫 스타트 지점 === ( 1 * 5 + 1 === 6 )
- 끝 그룹의 인덱스 = 시작 페이지 + 그룹의 크기 - 1
> 6 + 5 - 1 === 10번 그룹
### 이전 버튼 혹은 다음 버튼
> 다음 그룹으로 인덱스 변경 === (현재 그룹 + 1) X 그룹의 크기 + 1
> (0 + 1) X 5 + 1 === 6번 인덱스가 시작점
> 이전 그룹으로 인덱스 변경 === (현재 그룹 - 1) X 그룹의 크기 + 1
> (1 - 1) X 5 + 1 === 1번 인덱스가 시작점
1-3. 페이지네이션 실습 코드
index.html (웹 페이지 화면)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div>
<div>
<div>로그인한 유저는? : <span id="login_user"></span></div>
<label for="">아이디</label>
<input type="text" id="login_input">
<button id="login_btn">로그인</button>
<button id="logout_btn">로그아웃</button>
</div>
<h1>게시판</h1>
<form id="form_wrap">
<label for="">검색창</label><br>
<input type="text" id="search_input"><br>
<label for="">글 제목</label> <br>
<input type="text" name="title"> <br>
<label for="">글 내용</label> <br>
<textarea name="content"></textarea> <br>
<button>글 입력</button>
</form>
<div id="content_wrap"></div>
<div id="pagination"></div>
</div>
</body>
<script src="./index.js"></script>
</html>
index.js (페이지네이션 기능 코드)
이 코드에서는 전체 페이지를 보여줄 갯수를 5개로 설정하고, 현재 바라보는 페이지를 1로 설정하였습니다.
// 로그인 상태는 쿠키의 값이 있으면 로그인 상태다.
// 쿠키값을 가지고 유저정보 검증
// 쿠키도 결국 브라우저에 저장되는 문자열의 형태
// 데이터 베이스의 유저정보
const user = {
uid : ""
}
const PAGENUM = 5; // 전체 페이지
let pageIndex = 1; // 처음 바라보는 페이지
// 게시글을 담을 배열
// 저장한 값이 있으면 값을 가져와야한다.
console.log(localStorage.getItem("comment"));
const localStorageValue = JSON.parse(localStorage.getItem("comment")) // JSON 문자열을 객체의 형태로 형변환
const arr = localStorageValue || [];
// 값이 있으면 가져오고 없으면 빈배열로 초기화
// | : 값이 있는지 검사해서 있으면 1 없으면 0을 반환
// || : 값이 있으면 그 값을 반환한다.
// || -> 앞에 값이 있으면 앞에 값을 반환 없으면 뒤에 값을 반환
console.log(arr);
// Create
class Comment {
constructor(title, content){
this.uid = user.uid;
this.title = title;
this.content = content;
}
}
// title , cotnent 매개변수를 받아서 입력한 값의 빈 공백을 빼고
const addComment = (title, content) => {
if(title.trim() === "" || content.trim() === "") return ; // 글 입력를 못하게 한다.
const insatnce = new Comment(title.trim(), content.trim());
arr.push(insatnce);
// 문자열을 형변환 할 수 없기 때문에 JSON 문자열로 변환하여 로컬스토리지에 저장
// 저장한 것을 가져올 부분을 코딩
localStorage.setItem("comment", JSON.stringify(arr));
}
// Read
// 요소를 생성하는 함수 기능
const createContent = (index, search) => {
let item;
if(search){
item = search[index];
} else
item = arr[index];
// 데이터의 object를 받아서 화면에 렌더링할 수 있도록
const ul = document.createElement("ul"); // ul 요소 생성
const li_uid = document.createElement("li"); // uid li 요소 생성
const li_title = document.createElement("li"); // title li 요소 생성
const li_content = document.createElement("li"); // content li 요소 생성
/*
<ul>
<li></li>
<li></li>
<li></li>
</ul>
*/
ul.append(li_uid, li_title, li_content); // ul 요소의 자식요소로 li_uid, li_title, li_content 를 추가
// appendChild() : 하나의 요소만 추가할 수 있다.
// 댓글 내용에 대한 요소를 구조분해 할당
const {uid, title, content } = item;
li_uid.innerHTML = uid;
li_title.innerHTML = title;
li_content.innerHTML = content;
// pageIndex * PAGENUM
// index = 0
// index = 1
// index = 2
// index = 3
// index = 4
ul.onclick = () => {
location.href = `../detail/index.html?index=${ index + (pageIndex - 1 )* PAGENUM }`;
}
content_wrap.append(ul);
}
const render = (arr, search = false) => {
content_wrap.innerHTML = "";
arr.forEach((el, index) => {
// 배열의 갯수만큼 순회
if(search) {
createContent(index, arr)
} else {
createContent(index);
}
})
}
render(arr);
// 여기서 e는 폼 이벤트를 발생한 타켓을 의미
// submit 이벤트가 실행되면 addCommnet 함수가 호출된다
form_wrap.onsubmit = (e) => {
e.preventDefault(); // 새로고침을 막는다.
const { title , content} = e.target;
addComment(title.value, content.value);
console.log(arr);
title.value = ""
content.value = ""
render(arr);
}
// onkeydown은 value값이 할당되기 전에 콜백함수가 호출된다.
// value 값이 밀린것처럼 보임
search_input.onkeyup = (e) => {
console.log("뭐가 눌렷어");
console.log(e.target.value);
const arrTemp = [...arr]; // 얕은 복사 하여 새로운 배열을 만든다
// "".startsWith() 문자열이 매개변수로 전달한 문자열로 시작되는지 확인
const searchArr = arrTemp.filter((el) => el.title.startsWith(e.target.value));
console.log(searchArr);
render(searchArr, true);
}
const paginationCreate = () => {
const total = arr.length; // 전체글 갯수를 가져오고
const pages = Math.floor((total + PAGENUM - 1) / PAGENUM);
console.log(pages);
console.log(total);
for (let i = 0; i < pages; i++) {
const span = document.createElement("span");
span.innerHTML = i + 1;
span.onclick = () => {
pageIndex = i + 1;
paginationContent(pageIndex);
}
pagination.append(span);
}
}
// Content를 반환하는 메서드
const paginationContent = (index) => {
// (현재 페이지 인덱스 - 1) x 페이지의 글 갯수
let pagingContent = [...arr].splice((index - 1) * PAGENUM, PAGENUM);
console.log(pagingContent);
render(pagingContent, true);
}
paginationCreate();
paginationContent(pageIndex);
// 쿠키의 내용은 여러번 호출될 수 있다.
// 재사용성을 위해서 기능으로 만들자
// 만료 시간 지정안한 쿠키는 세션으로 만료시간이 지정되고 세션은 브라우저를 종료하면 사라진다.
// 쿠키의 삭제는 만료시간을 과거의 값으로 덮어씌우면 쿠키가 삭제된다.
const setCookie = (key, value, time) => {
let date = new Date();
date.setTime(date.getTime() + time * 24 * 60 * 60 * 1000);
// console.log(date.toUTCString());
document.cookie = `${key}=${value}; expires=${date.toUTCString()}; path=/;`
}
const deleteCookie = (key) => {
document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`
}
const getCookie = (key) => {
console.log(document.cookie);
let result;
// 쿠키의 값이 여러개일때 ; 으로 구분
let arr = document.cookie.trim().split(";");
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[i].trim().split('='); // 빈 공백을 제거하고 = 구문을 잘라서 배열로 만든다
if(key === arr[i][0]) {
result = arr[i][1];
}
}
console.log(result);
return result;
}
if(getCookie('login')){
login_user.innerHTML = getCookie('login');
user.uid = getCookie('login');
}
login_btn.onclick = () => {
login_input.value
setCookie('login', login_input.value, 1);
setCookie('login2', login_input.value, 1);
location.reload(); // 페이지 새로고침
}
logout_btn.onclick = () => {
deleteCookie('login');
location.reload(); // 페이지 새로고침
}
// 쿠키의 값이 있으면 로그인이 유지되는 상태가
style.css (스타일 코드)
#content_wrap ul {
display: flex;
list-style: none;
margin: 0;
cursor: pointer;
width: max-content;
padding: 0;
box-sizing: border-box;
border: 1px solid;
}
#content_wrap ul:hover {
border : 1px solid greenyellow;
}
#content_wrap li {
width: 100px;
border: 1px solid;
box-sizing: border-box;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
word-wrap: break-word;
white-space: nowrap;
}
#pagination {
display: flex;
}
#pagination span {
display: block;
padding: 10px;
border: 1px solid;
box-sizing: border-box;
cursor: pointer;
}
#pagination span:hover {
background-color: coral;
color : black;
}
실행화면
결론
페이지네이션을 사용하면, 많은 양의 데이터를 효율적으로 관리하고, 사용자의 페이지 렌더링 시간을 최적화 할 수 있습니다.
LIST
'자바스크립트 기록' 카테고리의 다른 글
[자바스크립트 문법] replace( ) , map( ), split( ) 메서드 🧑💻 (0) | 2025.02.10 |
---|---|
[자바스크립트 비동기 문법] 콜백지옥🔥🔥과 콜백지옥을 해결할 Async Await 💊💊 (2) | 2025.02.06 |
[자바스크립트 문법] 1급 객체란? (0) | 2025.02.04 |
[자바스크립트 문법] 클로저(Closure)란? (2) | 2025.02.04 |
[자바스크립트 비동기 문법] Promise(프로미스)란? (1) | 2025.02.04 |