본문 바로가기
자바스크립트(Javascript)

Pagination 기능 만들기

by 즐거운코딩 2023. 11. 3.
반응형

대용량의 데이터를 한꺼번에 화면에 표출하게 되면 데이터를 로딩하는 시간도 많이 소요되고, 사용자가 보기에도 불편함이 많이 존재하게 됩니다.

사용자 편의성을 위해 일반적으로 사용하는 페이지를 나눠서 보여주는 pagination 기능을 아래의 예시를 통해 적용해보겠습니다.

페이지를 나눠서 표출하는 방법에는 다양한 방법이 있겠으나 이번 예시에서는 Node.js, Express, MongoDB 환경에서 기능을 구현하였습니다.

 

1.  기능 정의

- 표출할 전체 데이터 수를 확인하기

- 한 페이지에 표출할 목록 갯수 정하기

- 페이지당 목록 개수에 따른 페이지수 확정

- 페이지 이동시 해당 페이지 목록에 해당되는 데이터만 불러오기

- 페이지 목록 표출은 Bootstrap 적용

 

2.  페이지 생성 함수 정의

utils>pagingFunc.js 파일 생성합니다.

pagingFunc 함수에 현재 page와 전체 데이터 갯수 totalList를 넘겨줍니다.

함수내에서 한 페이지 최대 표출 갯수(maxList) 와 하단에 표시할 페이지수의 단위(maxPage)를 지정합니다. (1), (2)

예시에서는 한 페이지에 20개 목록이 보여지며, 10개 페이지 단위로 이전, 이후 이동하도록 설정합니다.

 

현재 페이지 정보를 받으면 쿼리데이터는 문자여서 숫자로 바꿔 currentPage로 설정하고, 페이지 정보가 없으면 첫 페이지가 보여지도록 합니다.(3)

페이지 이동에 따라 불러올 데이터를 조정하는 것을 hideList로 설정합니다. 2 페이지이상 넘어가면 이전 페이지까지의 데이터 수를 계산합니다.(4)

전체 페이지수 totalPage는 전체 리스트를 한 페이지 최대리스트로 나눠서 계산합니다.(5)

현재 페이지로 들어온 값이 최대 페이지번호를 넘어가는 경우 최대 페이지번호를 현재 페이지번호로 바꿔줍니다. (6)

현재 페이지번호 기준으로 시작페이지번호(7)와 끝나는 페이지번호(8)을 지정합니다.

단, 끝나는 페이지(10개 단위)보다 최대 페이지번호가 적으면 최대 페이지번호 까지만 표출되도록 합니다.(9)

계산된 페이지 관련 데이터를 회신합니다. (10)

module.exports.pagingFunc = (page, totalList) => {
  const maxList = 20; // (1) 표출할 최대 갯수
  const maxPage = 10; // (2) 최대 페이지 갯수
  let currentPage = page ? parseInt(page) : 1; // (3) 쿼리 페이지 수 가져오기
  const hideList = page === 1 ? 0 : (page - 1) * maxList; // (4) DB에서 제외하고 불러올 리스트 갯수
  const totalPage = Math.ceil(totalList / maxList); // (5) 총 페이징해야할 페이지 수

  if (currentPage > totalPage) {
    // (6)
    currentPage = totalPage;
  }

  const startPage = Math.floor((currentPage - 1) / maxPage) * maxPage + 1; // (7)
  let endPage = startPage + maxPage - 1; // (8)

  if (endPage > totalPage) {
    // (9)
    endPage = totalPage;
  }
  console.log("maxPage:", maxPage);
  return {
    startPage,
    endPage,
    hideList,
    maxList,
    maxPage,
    totalPage,
    currentPage,
  }; // (10)
};

 

3. 페이지번호 적용할 화면에 pagingFunc 함수 적용하기

전체 리스트를 표출하는 index page화면에 pagingFunc함수를 적용하고 리턴 받은 값을 rendering page로 넘겨줍니다.

url query의 parameter로 page number를 가져옵니다.

표출할 데이터 갯수를 데이터베이스에서 불러옵니다. (Tourinfo.countDocuments({}))

pagingFunc 함수에 현재 페이지번호와 전체 데이터 갯수를 넘겨주고, 

시작페이지, 마지막페이지, 가져올 데이터 순서, 최대 표출리스트, 한 화면내 최대페이지수, 전체페이지수, 현재페이지 정보를 받아옵니다.

해당 정보로 한 페이지에 표출할 데이터를 가져옵니다. (Tourinfo.find({}).skip(hideList).limit(maxList))

실제 화면에 표출하기 위해 render 의 속성값으로 넘겨줍니다.

module.exports.index = async (req, res) => {
  const page = Number(req.query.page);
  console.log("page:", page);
  const totalList = await Tourinfo.countDocuments({});
  console.log(totalList);
  let {
    startPage,
    endPage,
    hideList,
    maxList,
    maxPage,
    totalPage,
    currentPage,
  } = pagingFunc(page, totalList);
  const campgrounds = await Tourinfo.find({}).skip(hideList).limit(maxList);
  const campgroundsAll = await Tourinfo.find({});

  res.render("campgrounds/index", {
    campgrounds,
    campgroundsAll,
    cities,
    startPage,
    endPage,
    hideList,
    maxList,
    maxPage,
    totalPage,
    currentPage,
  });
};

 

4. 웹페이지 화면 구성하기

페이지 정보를 받아 아래와 같이 페이지를 표출합니다. 표출 UI는 Bootstrap의 Pagination component를 참조하였습니다.

현재 페이지번호만 active하게 보이도록 조정합니다.

<% if (startPage > 0) { %>
<nav aria-label="Page navigation example">
  <ul class="pagination justify-content-center">
    <% if (startPage > maxPage) { %>
    <li class="page-item">
      <a
        class="page-link"
        href="/campgrounds/?page=<%= startPage-1 %>"
        aria-label="Previous"
      >
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
    <% } else { %>
    <li class="page-item disabled">
      <a class="page-link" href="#" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
    <% } %> <% for ( i = startPage; i <= endPage ;i++) { %>
    <li class="page-item">
      <a class="page-link <%= currentPage === i && "active" %>" href="/campgrounds/?page=<%= i %>"><%=i %></a>
    </li>
    <% } %> <% if (endPage < totalPage ) { %>
    <li class="page-item">
      <a
        class="page-link"
        href="/campgrounds/?page=<%= endPage+1 %>"
        aria-label="Next"
      >
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
    <% } else { %>
    <li class="page-item">
      <a class="page-link disabled" href="#" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
    <% } %>
  </ul>
</nav>
<% } %>

 

실제 표출되는 화면은 아래와 같습니다.

<<  , >> 로 10개 페이지 단위 이동이 가능하며, 현재 페이지번호가 active button 으로 표출됩니다. 

 

반응형