vuejs:vue3:paginator

Paginator

この実装を Vue3 用に移植してみました。

https://github.com/lokyoung/vuejs-paginate/blob/master/src/components/Paginate.vue

実際にリストに実装しての確認は、まだしていません。。。

import { onBeforeUpdate, ref, computed } from 'https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.2/vue.esm-browser.js';
 
const Paginator = {
  template: `
  <component is="style">
    ul.paginator a { cursor: pointer; }
  </component>
  <ul class="paginator" :class="containerClass" v-if="!noLiSurround">
    <li v-if="firstLastButton" :class="[pageClass, firstPageSelected() ? disabledClass : '']">
      <a :class="pageLinkClass" :tabindex="firstPageSelected() ? -1 : 0" v-html="firstButtonText"
         @click="selectFirstPage()" @keyup.enter="selectFirstPage()"
      ></a>
    </li>
 
    <li v-if="!(firstPageSelected() && hidePrevNext)" :class="[prevClass, firstPageSelected() ? disabledClass : '']">
      <a :class="prevLinkClass" :tabindex="firstPageSelected() ? -1 : 0" v-html="prevText"
         @click="prevPage()" @keyup.enter="prevPage()"
      ></a>
    </li>
 
    <li v-for="page in pages" :class="[
      pageClass, page.selected ? activeClass : '',
      page.disabled ? disabledClass : '',
      page.breakView ? breakViewClass: '']"
    >
      <a v-if="page.breakView" :class="[pageLinkClass, breakViewLinkClass]" tabindex="0">
        <slot name="breakViewContent">{{ breakViewText }}</slot>
      </a>
      <a v-else-if="page.disabled" :class="pageLinkClass" tabindex="0">{{ page.content }}</a>
      <a v-else :class="pageLinkClass" tabindex="0"
        @click="handlePageSelected(page.index + 1)"
        @keyup.enter="handlePageSelected(page.index + 1)"
      >{{ page.content }}</a>
    </li>
 
    <li v-if="!(lastPageSelected() && hidePrevNext)" :class="[nextClass, lastPageSelected() ? disabledClass : '']">
      <a :class="nextLinkClass" :tabindex="lastPageSelected() ? -1 : 0" v-html="nextText"
         @click="nextPage()" @keyup.enter="nextPage()"
      ></a>
    </li>
 
    <li v-if="firstLastButton" :class="[pageClass, lastPageSelected() ? disabledClass : '']">
      <a :class="pageLinkClass" :tabindex="lastPageSelected() ? -1 : 0" v-html="lastButtonText"
         @click="selectLastPage()" @keyup.enter="selectLastPage()" 
      ></a>
    </li>
  </ul>
 
  <div :class="containerClass" v-else>
    <a v-if="firstLastButton" tabindex="0" v-html="firstButtonText"
      :class="[pageLinkClass, firstPageSelected() ? disabledClass : '']"
      @click="selectFirstPage()" @keyup.enter="selectFirstPage()">
    </a>
    <a v-if="!(firstPageSelected() && hidePrevNext)" tabindex="0" v-html="prevText"
       :class="[prevLinkClass, firstPageSelected() ? disabledClass : '']"
       @click="prevPage()" @keyup.enter="prevPage()"
    ></a>
    <template v-for="page in pages">
      <a v-if="page.breakView" tabindex="0">
        <slot name="breakViewContent" :class="[pageLinkClass, breakViewLinkClass, page.disabled ? disabledClass : '']">
          {{ breakViewText }}
        </slot>
      </a>
      <a v-else-if="page.disabled" :class="[pageLinkClass, page.selected ? activeClass : '', disabledClass]" tabindex="0">
        {{ page.content }}
      </a>
      <a v-else :class="[pageLinkClass, page.selected ? activeClass : '']" tabindex="0"
         @click="handlePageSelected(page.index + 1)" @keyup.enter="handlePageSelected(page.index + 1)"
      >
        {{ page.content }}
      </a>
    </template>
    <a v-if="!(lastPageSelected() && hidePrevNext)" tabindex="0" v-html="nextText"
       :class="[nextLinkClass, lastPageSelected() ? disabledClass : '']"
       @click="nextPage()" @keyup.enter="nextPage()"
    ></a>
    <a v-if="firstLastButton" tabindex="0" v-html="lastButtonText"
       :class="[pageLinkClass, lastPageSelected() ? disabledClass : '']"
       @click="selectLastPage()" @keyup.enter="selectLastPage()"
    ></a>
  </div>
  `,
  props: {
    value:              { type: Number },
    pageCount:          { type: Number,   required: true },
    forcePage:          { type: Number },
    clickHandler:       { type: Function, default: () => {} },
    pageRange:          { type: Number,   default: 3 },
    marginPages:        { type: Number,   default: 1 },
    prevText:           { type: String,   default: '<' },
    nextText:           { type: String,   default: '>' },
    breakViewText:      { type: String,   default: '…'    },
    containerClass:     { type: String,   default: 'pagination pagination-sm pull-right' },
    pageClass:          { type: String },
    pageLinkClass:      { type: String },
    prevClass:          { type: String },
    prevLinkClass:      { type: String },
    nextClass:          { type: String },
    nextLinkClass:      { type: String },
    breakViewClass:     { type: String },
    breakViewLinkClass: { type: String },
    activeClass:        { type: String,  default: 'active' },
    disabledClass:      { type: String,  default: 'disabled' },
    noLiSurround:       { type: Boolean, default: false },
    firstLastButton:    { type: Boolean, default: true },
    firstButtonText:    { type: String,  default: '<<' },
    lastButtonText:     { type: String,  default: '>>' },
    hidePrevNext:       { type: Boolean, default: false }
  },
  setup(props, context) {
    const innerValue = ref(1)
 
    const selected = computed({
      get: function() {
        return props.value || innerValue.value
      },
      set: function(newValue) {
        innerValue.value = newValue
      }
    })
 
    const pages = computed(function() {
      let items = {}
      if (props.pageCount <= props.pageRange) {
        for (let index = 0; index < props.pageCount; index++) {
          let page = {
            index: index,
            content: index + 1,
            selected: index === (selected - 1)
          }
          items[index] = page
        }
      } else {
        const halfPageRange = Math.floor(props.pageRange / 2)
        let setPageItem = index => {
          let page = {
            index: index,
            content: index + 1,
            selected: index === (selected - 1)
          }
          items[index] = page
        }
        let setBreakView = index => {
          let breakView = {
            disabled: true,
            breakView: true
          }
          items[index] = breakView
        }
        // 1st - loop thru low end of margin pages
        for (let i = 0; i < props.marginPages; i++) {
          setPageItem(i);
        }
        // 2nd - loop thru selected range
        let selectedRangeLow = 0;
        if (selected.value - halfPageRange > 0) {
          selectedRangeLow = selected.value - 1 - halfPageRange;
        }
        let selectedRangeHigh = selectedRangeLow + props.pageRange - 1;
        if (selectedRangeHigh >= props.pageCount) {
          selectedRangeHigh = props.pageCount - 1;
          selectedRangeLow = selectedRangeHigh - props.pageRange + 1;
        }
        for (let i = selectedRangeLow; i <= selectedRangeHigh && i <= props.pageCount - 1; i++) {
          setPageItem(i);
        }
        // Check if there is breakView in the left of selected range
        if (selectedRangeLow > props.marginPages) {
          setBreakView(selectedRangeLow - 1)
        }
        // Check if there is breakView in the right of selected range
        if (selectedRangeHigh + 1 < props.pageCount - props.marginPages) {
          setBreakView(selectedRangeHigh + 1)
        }
        // 3rd - loop thru high end of margin pages
        for (let i = props.pageCount - 1; i >= props.pageCount - props.marginPages; i--) {
          setPageItem(i);
        }
      }
      return items
    })
 
    onBeforeUpdate(() => {
      if (props.forcePage === undefined) return
      if (props.forcePage !== selected.value) {
        selected.value = props.forcePage
      }
    })
 
    function handlePageSelected(value) {
      if (selected.value === value) return
      innerValue.value = value
      context.emit('input', value)
      props.clickHandler(value)
    }
    function prevPage() {
      if (selected.value <= 1) return
      handlePageSelected(selected.value - 1)
    }
    function nextPage() {
      if (selected.value >= props.pageCount) return
      handlePageSelected(selected.value + 1)
    }
    function firstPageSelected() {
      return selected.value === 1
    }
    function lastPageSelected() {
      return (selected.value === props.pageCount) || (props.pageCount === 0)
    }
    function selectFirstPage() {
      if (selected.value <= 1) return
      handlePageSelected(1)
    }
    function selectLastPage() {
      if (selected.value >= props.pageCount) return
      handlePageSelected(props.pageCount)
    }
 
    return {
      innerValue,
      selected,
      pages,
      handlePageSelected,
      prevPage,
      nextPage,
      firstPageSelected,
      lastPageSelected,
      selectFirstPage,
      selectLastPage
    }
  }
};
export default Paginator;
<html>
<div id="app">
  <paginator :page-count="500" :click-handler="clickFunc">
  </paginator>
</div>
 
<script type="module">
import { createApp } from 'https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.2/vue.esm-browser.js';
import Paginator from '/_export/code/vuejs/vue3/paginator?codeblock=0';
 
const App = {
  components: {
    paginator : Paginator 
  },
  data() {
    return { currentPage: 1 }
  },
  methods: {
    clickFunc(value) {
      alert(value);
      this.currentPage = value;
    }
  }
}
createApp(App).mount('#app')
</script>
</html>

  • vuejs/vue3/paginator.txt
  • 最終更新: 2022/11/15 18:50
  • by admin