Last active
          October 5, 2021 03:58 
        
      - 
      
 - 
        
Save hartmut-co-uk/0f01f852c3efdf97b3286cff8159b6e7 to your computer and use it in GitHub Desktop.  
    SSR supporting nuxt pagination vue component, pagination as links (`nuxt-link` -> vue-router) & query params (configurable param names). Data/API loading paginated results is done via nuxt `fetch` & `watchQuery`.
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | <template> | |
| <div class="pagination"> | |
| <div class="inner"> | |
| <template v-if="showPrev"> | |
| <nuxt-link v-if="prev" :to="routeToPage(prev)" class="page previous">Previous</nuxt-link> | |
| <span v-else class="page previous disabled">Previous</span> | |
| </template> | |
| <template v-for="it in prevPages"> | |
| <nuxt-link v-if="it !== -1" :key="it" :to="routeToPage(it)" class="page">{{ it }}</nuxt-link> | |
| <span v-else :key="it" class="page more">...</span> | |
| </template> | |
| <span class="page current">{{ page }}</span> | |
| <template v-for="it in nextPages"> | |
| <nuxt-link v-if="it !== -1" :key="it" :to="routeToPage(it)" class="page">{{ it }}</nuxt-link> | |
| <span v-else :key="it" class="page more">...</span> | |
| </template> | |
| <template v-if="showNext"> | |
| <nuxt-link v-if="next" :to="routeToPage(next)" class="page next">Next</nuxt-link> | |
| <span v-else class="page next disabled">Next</span> | |
| </template> | |
| </div> | |
| </div> | |
| </template> | |
| <script lang="ts"> | |
| import { Component, Prop, Vue } from 'nuxt-property-decorator' | |
| @Component({ | |
| components: {}, | |
| }) | |
| export default class RouterPagination extends Vue { | |
| @Prop({ required: true }) readonly page: number | |
| @Prop({ required: true }) readonly size: number | |
| @Prop({ required: true }) readonly totalElements: number | |
| @Prop({ default: 10 }) readonly PAGE_SIZE_DEFAULT: number | |
| @Prop({ default: 100 }) readonly PAGE_SIZE_MAX: number | |
| @Prop({ default: 100 }) readonly PAGE_NUMBER_MAX: number | |
| @Prop({ default: 'page' }) readonly pageParamName: string | |
| @Prop({ default: 'size' }) readonly sizeParamName: string | |
| @Prop({ default: 9 }) readonly maxPagesToList: number | |
| @Prop({ default: true }) readonly showPrev: boolean | |
| @Prop({ default: true }) readonly showNext: boolean | |
| @Prop({ default: null }) readonly pageSizeOptions: number[] | null | |
| get sizeSafe () { | |
| return Math.max(1, Math.min(this.size, this.PAGE_SIZE_MAX)) | |
| } | |
| get pageSafe () { | |
| return Math.max(1, Math.min(this.page, this.PAGE_NUMBER_MAX)) | |
| } | |
| get totalElementsSafe () { | |
| return Math.max(0, this.totalElements) | |
| } | |
| get prev () { | |
| return this.prevPage(this.pageSafe) | |
| } | |
| get next () { | |
| return this.nextPage(this.pageSafe) | |
| } | |
| get prevPages () { | |
| const pages: number[] = [] | |
| let it: number | null = this.pageSafe | |
| let iterations = this.maxPagesToList - 1 - Math.min(Math.floor(this.maxPagesToList / 2), this.noOfPagesAfter) - (this.showMorePrev ? 2 : 0) | |
| while (iterations > 0 && it !== null) { | |
| it = this.prevPage(it) | |
| if (it !== null) { | |
| pages.unshift(it) | |
| } | |
| iterations-- | |
| } | |
| if (this.showMorePrev) { | |
| pages.unshift(-1) | |
| pages.unshift(1) | |
| } | |
| return pages | |
| } | |
| get nextPages () { | |
| const pages: number[] = [] | |
| let it: number | null = this.pageSafe | |
| let iterations = this.maxPagesToList - 1 - Math.min(Math.floor(this.maxPagesToList / 2), this.noOfPagesBefore) - (this.showMoreNext ? 2 : 0) | |
| while (iterations > 0 && it !== null) { | |
| it = this.nextPage(it) | |
| if (it !== null) { | |
| pages.push(it) | |
| } | |
| iterations-- | |
| } | |
| if (this.showMoreNext) { | |
| pages.push(-1) | |
| pages.push(this.lastPage) | |
| } | |
| return pages | |
| } | |
| get lastPage () { | |
| return Math.min(Math.ceil(this.totalElementsSafe / this.sizeSafe), this.PAGE_NUMBER_MAX) | |
| } | |
| get noOfPagesBefore () { | |
| return this.pageSafe - 1 | |
| } | |
| get noOfPagesAfter () { | |
| return this.lastPage - this.pageSafe | |
| } | |
| get showMorePrev () { | |
| return this.maxPagesToList - Math.min(Math.floor(this.maxPagesToList / 2), this.noOfPagesAfter) <= this.noOfPagesBefore | |
| } | |
| get showMoreNext () { | |
| return this.maxPagesToList - Math.min(Math.floor(this.maxPagesToList / 2), this.noOfPagesBefore) <= this.noOfPagesAfter | |
| } | |
| prevPage (it: number): number | null { | |
| const prev = it - 1 | |
| return prev >= 1 ? prev : null | |
| } | |
| nextPage (it: number): number | null { | |
| const next = it + 1 | |
| if (next <= this.PAGE_NUMBER_MAX && it * this.sizeSafe < this.totalElementsSafe) { | |
| return next | |
| } | |
| return null | |
| } | |
| routeToPage (page: number) { | |
| console.debug('routeToPage', page) | |
| const query: any = { | |
| ...this.$nuxt.$route.query, | |
| } | |
| if (page <= 1) { | |
| delete query[this.pageParamName] | |
| } else { | |
| query[this.pageParamName] = page | |
| } | |
| console.debug('query', query) | |
| return { query: query } | |
| } | |
| } | |
| </script> | |
| <style lang="stylus" scoped> | |
| .pagination | |
| text-align center | |
| .inner | |
| margin auto 0 | |
| display inline-block | |
| a:focus, a:hover, span:focus:not(.current), span:hover:not(.current) | |
| background-color: #edf1f4 | |
| border-color: #e1e4e8 | |
| text-decoration: none | |
| .page | |
| -webkit-user-select: none | |
| background: #fff | |
| border: 1px solid #e1e4e8 | |
| color: #0366d6 | |
| cursor: pointer | |
| float: left | |
| font-size: 13px | |
| font-style: normal | |
| font-weight: 600 | |
| margin-left: -1px | |
| padding: 7px 12px | |
| position: relative | |
| user-select: none | |
| vertical-align: middle | |
| white-space: nowrap | |
| .page.previous | |
| border-bottom-left-radius: 3px | |
| border-top-left-radius: 3px | |
| margin-left: 0 | |
| .page.next | |
| border-bottom-right-radius: 3px | |
| border-top-right-radius: 3px | |
| margin-right: 0 | |
| .page.current | |
| background-color: #0366d6 | |
| border-color: #0366d6 | |
| color: #fff | |
| .page.disabled, .page.more | |
| background-color: #edf1f4 | |
| color: #d1d5da | |
| cursor: default | |
| a | |
| text-decoration none | |
| </style> | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment