vue3 - paginate component on redgoose note

vue3 - paginate component

Nest: Development Category: Javascript 2021-12-25

컴포넌트 백업용으로 보관해둔다.
vue3composition-api 환경에서 사용할 수 있다.

<template>
<nav class="paginate">
  <div class="paginate__wrap">
    <button
      v-if="false"
      type="button"
      title="to first page"
      :disabled="props.modelValue <= 1"
      :class="[ 'paginate-item', 'paginate-item--far' ]"
      @click="onFirstPage">
      first
    </button>
    <button
      type="button"
      :title="`to ${props.range} page prev`"
      :disabled="pageBlock <= 0"
      :class="[ 'paginate-item', 'paginate-item--range' ]"
      @click="onPrevRange">
      range prev
    </button>
    <button
      v-if="false"
      type="button"
      title="to prev page"
      :disabled="props.modelValue <= 1"
      :class="[ 'paginate-item', 'paginate-item--near' ]"
      @click="onPrevPage">
      prev page
    </button>
    <template v-if="pages.length > 0">
      <button
        v-for="item in pages"
        type="button"
        :disabled="item.active"
        :title="`${item.key} page`"
        :class="[ 'paginate-item', 'paginate-item--number' ]"
        @click="go(item.key)">
        {{item.key}}
      </button>
    </template>
    <button
      v-if="false"
      type="button"
      title="to next page"
      :disabled="pageCount <= modelValue"
      :class="[ 'paginate-item', 'paginate-item--near' ]"
      @click="onNextPage">
      next page
    </button>
    <button
      type="button"
      :title="`to ${props.range} page next`"
      :disabled="pageBlock >= pageBlockTotal"
      :class="[ 'paginate-item', 'paginate-item--range' ]"
      @click="onNextRange">
      range next
    </button>
    <button
      v-if="false"
      type="button"
      title="to last page"
      :disabled="modelValue >= pageCount"
      :class="[ 'paginate-item', 'paginate-item--far' ]"
      @click="onLastPage">
      last
    </button>
  </div>
</nav>
</template>

<script setup>
import { computed } from 'vue';
const props = defineProps({
  modelValue: { type: Number, default: 1 },
  total: { type: Number, default: 0 },
  size: { type: Number, default: 10 },
  range: { type: Number, default: 5 },
});
const emits = defineEmits([ 'update:modelValue' ]);
const pageCount = computed(() => (Math.ceil(props.total / props.size)));
const offset = computed(() => ((props.modelValue - 1) * props.size));
const pageBlock = computed(() => (Math.floor((props.modelValue - 1) / props.range)));
const pageBlockTotal = computed(() => (Math.floor((pageCount.value - 1) / props.range)));
const pages = computed(() => {
  let items = [];
  let startPage = pageBlock.value * props.range + 1;
  for (let i = 1; i < props.range + 1 && startPage <= pageCount.value; i++, startPage++)
  {
    items[i - 1] = {
      key: startPage,
      active: (startPage === props.modelValue),
    };
  }
  // check empty item
  let checkEmpty = false;
  items.forEach(o => {
    if (o.active) checkEmpty = true;
  });
  return checkEmpty ? items : [];
});

function onPrevPage()
{
  if (props.modelValue > 1) go(props.modelValue - 1);
}
function onNextPage()
{
  if (props.modelValue < pageCount.value) go(props.modelValue + 1);
}

function onPrevRange()
{
  if (props.modelValue > 1)
  {
    let n = props.modelValue - props.range;
    go((n > 1) ? n : 1);
  }
}
function onNextRange()
{
  if (pageBlock.value < pageBlockTotal.value)
  {
    let n = props.modelValue + props.range;
    go(n > pageCount.value ? pageCount.value : n);
  }
}

function onFirstPage()
{
  if (props.modelValue > 1) go(1);
}
function onLastPage()
{
  if (props.modelValue < pageCount.value) go(pageCount.value);
}

function go(page)
{
  if (props.modelValue !== page) emits('update:modelValue', page);
}
</script>

컴포넌트를 사용하는 부분은..

<template>
<Paginate v-model="state.page" :total="156" :size="10" :range="10"/>
</template>

<script setup>
import Paginate from './paginate.vue';
</script>