본문으로 바로가기

Vue.js 페이징처리(Pagination)

category JavaScript/Vue.js 2021. 9. 8. 13:29

뷰에서 처음으로 페이징처리 작업을 하는거라 미숙하긴 하지만

작업하면서 정리하는 차원에서 작성한 글입니다.

Nuxt와 vuex-pathify를 사용했습니다.

<template>
  <ul class="pagination-frame">
    <li @click="changeCurrentPage(
      (currentPage - pageCount) > 1 ? currentPage - pageCount : 1
    )">
      <a class="page-text">
        〈〈
      </a>
    </li>
    <li 
      class="page-left-btn"
      @click="changeCurrentPage(
        (currentPage - 1) > 1 ? currentPage - 1 : 1
      )"
    >
      <a class="page-text">
        〈
      </a>
    </li>
    
    <li 
      v-for="n in paginationUnits"
      :key="n"
      :class="[n === currentPage ? 'selected-page' : '', 'page-btn']"
      @click="changeCurrentPage(n)"
    >
      <a class="page-text">
        {{ n }}
      </a>
    </li>
    
    <li 
      class="page-right-btn"
      @click="changeCurrentPage(
        (currentPage + 1) < maxPage ? currentPage + 1 : maxPage
      )"
    >
      <a class="page-text">
        〉
      </a>
    </li>
    <li @click="changeCurrentPage(
      (currentPage + pageCount) < maxPage ? currentPage + pageCount : maxPage
    )">
      <a class="page-text">
        〉〉
      </a>
    </li>
  </ul>
</template>

<script>
import {
  get,
} from 'vuex-pathify'

export default {
  name: 'PaginationComponent',
  props: {
    countOfTotal: { // 총 목록 갯수
      type: Number,
      required: true,
    },
    listSize: { // 화면에 출력할 목록 갯수
      type: Number,
      default: 10,
    }
  },
  computed: {
    currentPage: get('adminSearch/currentPage'),

    maxPage() {  // 총 페이지 수(and 최대 페이지 번호)
      return Math.ceil(this.countOfTotal / this.listSize)
    },
    startPage() { // 페이지 시작 번호
      return (Math.trunc((this.currentPage - 1) / this.pageCount) * this.pageCount) + 1
    },
    endPage() { // 페이지 끝 번호
      let end = this.startPage + this.pageCount - 1
      return end < this.maxPage ? end : this.maxPage
    },
    paginationUnits() { // 화면에 표시할 페이지 배열..
      let units = []
      for(let num = this.startPage; num <= this.endPage; num++) {
        units.push(num)
      }
      return units
    },
  },
  data() {
    return {
      pageCount: 10, // 페이지 버튼 최대 갯수
    }
  },
  methods: {
    changeCurrentPage(page) { // 페이지 변경
      if(this.currentPage !== page) {
        this.$store.set('adminSearch/currentPage', page)
        // 변경된 페이지 전송
        this.$emit("changePage", page)
      }
    },
  },
}
</script>

<style lang="scss">
  /* 페이징처리 출력부 */
  .pagination-frame {
    height: 10%;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    list-style: none;
    margin: 1vh 0vw 0vh 0vw;
    padding: 0px;

    /* 드래그 막기 */
    -ms-user-select: none; 
    -moz-user-select: -moz-none;
    -khtml-user-select: none;
    -webkit-user-select: none;
    user-select: none;
  }
  /* 페이지 이동 버튼 */
  .pagination-frame > li {
    width: 1.55vw;
    height: 3vh;
    background-color: #fff;
    border: 1px solid rgb(211, 210, 211);
    text-align: center;
    padding: 3px 0vw;
    cursor: pointer;
  }
  .page-btn {
    margin: 0px 1px;
  }
  .page-left-btn {
    margin-right: 5px;
  }
  .page-right-btn {
    margin-left: 5px;
  }

  li:hover:not(.selected-page) {
    background-color: rgba(222, 222, 222, 0.3);
  }
  li.selected-page {
    background-color: rgb(222, 222, 222);
  }

  .page-text {
    text-decoration: none;
    cursor: pointer;
  }
  .page-text:hover {
    color: #000;
  }
  
  
</style>

결과 화면

 

Tailwind CSS + Vue.js

2022.08.02 추가

이번에 테일윈드로 몇몇 페이지를 새로 만들면서 처음부터 만들어보았는데

간단한 컴포넌트여서인지 아니면 평소에 위의 페이지네이션을 사용하다가 만들어서 그런지 몰라도

변경사항이 별로 없네요.. 하하

- 변경사항

1. 양쪽 끝의 Arrow 버튼의 기능을 method로 분리

2. css작업은 tailwind를 사용

3. 디자인은 동그랗게 변경

<template>
  <div class="w-full h-16 py-2 select-none">
    <div class="w-full h-full flex items-center justify-center">
      <ul class="flex pl-0 rounded list-none flex-wrap">
        <li>
          <a 
            class="first:ml-0 text-xs font-semibold flex w-8 h-8 mx-1 p-0 rounded-full items-center justify-center leading-tight relative border border-solid border-[#385492] bg-white text-[#385492] cursor-pointer hover:bg-[#385492] hover:opacity-75 fill-[#385492] hover:fill-white"
            @click="arrowEvent(-1, true)"
          >
            <svg class="w-4 h-4 stroke-0" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
              <path d="M6.85355 3.85355C7.04882 3.65829 7.04882 3.34171 6.85355 3.14645C6.65829 2.95118 6.34171 2.95118 6.14645 3.14645L2.14645 7.14645C1.95118 7.34171 1.95118 7.65829 2.14645 7.85355L6.14645 11.8536C6.34171 12.0488 6.65829 12.0488 6.85355 11.8536C7.04882 11.6583 7.04882 11.3417 6.85355 11.1464L3.20711 7.5L6.85355 3.85355ZM12.8536 3.85355C13.0488 3.65829 13.0488 3.34171 12.8536 3.14645C12.6583 2.95118 12.3417 2.95118 12.1464 3.14645L8.14645 7.14645C7.95118 7.34171 7.95118 7.65829 8.14645 7.85355L12.1464 11.8536C12.3417 12.0488 12.6583 12.0488 12.8536 11.8536C13.0488 11.6583 13.0488 11.3417 12.8536 11.1464L9.20711 7.5L12.8536 3.85355Z"/>
            </svg>
          </a>
        </li>
        <li>
          <a 
            class="first:ml-0 text-xs font-semibold flex w-8 h-8 mx-1 p-0 rounded-full items-center justify-center leading-tight relative border border-solid border-[#385492] bg-white text-[#385492] cursor-pointer hover:bg-[#385492] hover:opacity-75 fill-[#385492] hover:fill-white"
            @click="arrowEvent(-1, false)"
          >
            <svg class="w-4 h-4 stroke-0" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
              <path d="M8.84182 3.13514C9.04327 3.32401 9.05348 3.64042 8.86462 3.84188L5.43521 7.49991L8.86462 11.1579C9.05348 11.3594 9.04327 11.6758 8.84182 11.8647C8.64036 12.0535 8.32394 12.0433 8.13508 11.8419L4.38508 7.84188C4.20477 7.64955 4.20477 7.35027 4.38508 7.15794L8.13508 3.15794C8.32394 2.95648 8.64036 2.94628 8.84182 3.13514Z"/>
            </svg>
          </a>
        </li>

        <li
          v-for="unit in paginationUnits"
          :key="`page-${unit}`"
        >
          <a 
            class="first:ml-0 text-xs font-semibold flex w-8 h-8 mx-1 p-0 rounded-full items-center justify-center leading-tight relative border border-solid border-[#385492] hover:bg-[#385492] cursor-pointer"
            :class="[currentPage === unit ? 'bg-[#385492] text-white' : 'bg-white text-[#385492] hover:opacity-75 hover:text-white']"
            @click="setCurrentPage(unit)"
          >{{ unit }}</a>
        </li>

        <li>
          <a 
            class="first:ml-0 text-xs font-semibold flex w-8 h-8 mx-1 p-0 rounded-full items-center justify-center leading-tight relative border border-solid border-[#385492] bg-white text-[#385492] cursor-pointer hover:bg-[#385492] hover:opacity-75 fill-[#385492] hover:fill-white"
            @click="arrowEvent(1, false)"
          >
            <svg class="w-4 h-4 stroke-0" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
              <path d="M6.1584 3.13508C6.35985 2.94621 6.67627 2.95642 6.86514 3.15788L10.6151 7.15788C10.7954 7.3502 10.7954 7.64949 10.6151 7.84182L6.86514 11.8418C6.67627 12.0433 6.35985 12.0535 6.1584 11.8646C5.95694 11.6757 5.94673 11.3593 6.1356 11.1579L9.565 7.49985L6.1356 3.84182C5.94673 3.64036 5.95694 3.32394 6.1584 3.13508Z"/>
            </svg>
          </a>
        </li>
        <li>
          <a 
            class="first:ml-0 text-xs font-semibold flex w-8 h-8 mx-1 p-0 rounded-full items-center justify-center leading-tight relative border border-solid border-[#385492] bg-white text-[#385492] cursor-pointer hover:bg-[#385492] hover:opacity-75 fill-[#385492] hover:fill-white"
            @click="arrowEvent(1, true)"
          >
            <svg class="w-4 h-4 stroke-0" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
              <path d="M2.14645 11.1464C1.95118 11.3417 1.95118 11.6583 2.14645 11.8536C2.34171 12.0488 2.65829 12.0488 2.85355 11.8536L6.85355 7.85355C7.04882 7.65829 7.04882 7.34171 6.85355 7.14645L2.85355 3.14645C2.65829 2.95118 2.34171 2.95118 2.14645 3.14645C1.95118 3.34171 1.95118 3.65829 2.14645 3.85355L5.79289 7.5L2.14645 11.1464ZM8.14645 11.1464C7.95118 11.3417 7.95118 11.6583 8.14645 11.8536C8.34171 12.0488 8.65829 12.0488 8.85355 11.8536L12.8536 7.85355C13.0488 7.65829 13.0488 7.34171 12.8536 7.14645L8.85355 3.14645C8.65829 2.95118 8.34171 2.95118 8.14645 3.14645C7.95118 3.34171 7.95118 3.65829 8.14645 3.85355L11.7929 7.5L8.14645 11.1464Z"/>
            </svg>
          </a>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    countOfTotal: { // 전체 목록의 갯수
      type: Number,
      default: 132,
    },
    listSize: { // 한 페이지의 목록 최대 갯수
      type: Number,
      default: 10,
    },
  },
  computed: {
    maxPage() { // 최대 페이지 번호
      let page = Math.ceil(this.countOfTotal / this.listSize)
      return page === 0 ? 1 : page
    },
    startPage() { // 보여질 시작 페이지 번호
      return (Math.trunc((this.currentPage - 1) / this.pageCount) * this.pageCount + 1)
    },
    endPage() { // 보여질 마지막 페이지 번호
      let end = this.startPage + this.pageCount - 1
      return end < this.maxPage ? end : this.maxPage
    },
    paginationUnits() { // 화면에 표시할 페이지 배열..
      let units = []
      let num = this.startPage
      while(num <= this.endPage) {
        units.push(num++)
      }
      return units.length ? units : [1]
    },
  },
  data() {
    return {
      currentPage: 1, // 임시 현재 페이지
      pageCount: 10,  // 페이지 버튼 최대 갯수
    }
  },
  methods: {
    setCurrentPage(page) {  // 페이지 이동
      if(this.currentPage !== page) {
        this.currentPage = page
      }
    },
    arrowEvent(op, isDouble) {  // 좌우의 화살표 버튼 이벤트
      let num = isDouble ? this.pageCount : 1

      if(op === -1) {
        this.currentPage = (this.currentPage) - num > 1 ? this.currentPage - num : 1
        return
      }

      if(op === 1) {
        this.currentPage = (this.currentPage + num) < this.maxPage ? this.currentPage + num : this.maxPage
        return
      }
    },
  },
}
</script>

결과화면

반응형

'JavaScript > Vue.js' 카테고리의 다른 글

Vue 컴포넌트에 외부 스크립트 추가 (메모용)  (0) 2022.03.18
[vue-gtag] Google Analytics 공부  (0) 2022.01.11
Vuex-Pathify  (0) 2021.08.13
뷰 필터  (0) 2021.08.02
믹스인과 하이 오더 컴포넌트 비교 분석  (0) 2021.08.02