Skip to content

Instantly share code, notes, and snippets.

@gerardojbaez
Last active March 6, 2018 04:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gerardojbaez/eebd84f1d919afe6e016ac6b8712d19a to your computer and use it in GitHub Desktop.
Save gerardojbaez/eebd84f1d919afe6e016ac6b8712d19a to your computer and use it in GitHub Desktop.
Laravel's style pagination using Vue.
<!-- Inspired by Laravel Paginator. © Gerardo J. Báez <g@gerardobaez.com> 2017. Released with MIT License. -->
<template>
<ul class="pagination">
<li v-if="hasPrev()"><a href="javascript:void(0)" @click="prev()" class="prev">Previous</a></li>
<template v-for="page in getPageSlider()">
<li v-if="isNaN(page) === false">
<a href="javascript:void(0)" :class="{ 'active': currentPage == page }" @click="goToPage(page)">{{ page }}</a>
</li>
<li v-else class="blank">...</li>
</template>
<li v-if="hasNext()"><a href="javascript:void(0)" @click="next()" class="next">Next</a></li>
</ul>
</template>
<script>
export default {
props: {
currentPage: {
type: Number,
required: true
},
total: {
type: Number,
required: true
},
perPage: {
type: Number,
required: true
}
},
methods: {
/**
* Navigate to the next page (if there's one).
*/
next () {
if (this.hasNext()) {
this.goToPage(this.currentPage + 1)
}
},
/**
* Navigate to the previous page (if there's one).
*/
prev () {
if (this.hasPrev()) {
this.goToPage(this.currentPage - 1)
}
},
/**
* Determine if there's a previous page.
*
* @return {Boolean}
*/
hasPrev () {
return this.currentPage > 1
},
/**
* Determine if there's a next page.
*
* @return {Boolean}
*/
hasNext () {
return this.currentPage < this.getLastPage()
},
/**
* Get pagination slider.
*
* @return {Array}
*/
getPageSlider () {
if (this.getLastPage() < 10) {
// No need to split or build an advance pagination window, let's just use a simple one.
return this.getSmallSlider()
}
// Since the pagination can get big (20+ pages), we need to properly split and create small
// "windows" of page links. For example: 1, 2, ..., 3, 4, 5, 6, ..., 22, 23.
return _.filter(this.getFullSlider(), page => {
// Keep only numbers higher than 1 and the separator "...".
return page > 0 || page === '...'
})
},
/**
* Get small slider.
*
* @return {Array}
*/
getSmallSlider () {
return this.getPageRange(1, this.getLastPage())
},
/**
* Get full pagination slider.
*
* @return {Array}
*/
getFullSlider () {
if (this.currentPage < 6) {
// Don't split the beginning of the page range since we are close to it... This will return
// a range similar to 1, 2, 3, 4, 5, 6, ... 22
return this.getPageRange(1, 6).concat(['...'], this.getFinish())
} else if (this.currentPage > (this.getLastPage() - 4)) {
// Don't split the end of the page range since we are close to it... This will return
// a range similar to 1, 2, ..., 17, 18, 19, 20, 21, 22, 23
return this.getStart().concat(['...'], this.getPageRange(this.getLastPage() - 6, this.getLastPage()))
}
// Split the beginning and the end of the page range... This will return
// a range similar to 1, 2, ..., 3, 4, 5, 6, ..., 22, 23
return this.getStart().concat(['...'], this.getAdjacent(), ['...'], this.getFinish())
},
/**
* Get the start of the pagination window.
*
* @return {Array}
*/
getStart () {
return this.getPageRange(1, 2)
},
/**
* Get the end of the pagination window.
*
* @return {Array}
*/
getFinish () {
return this.getPageRange(this.getLastPage() - 1, this.getLastPage())
},
/**
* Get the adjacent pages.
*
* @return {Array}
*/
getAdjacent () {
return this.getPageRange(this.currentPage - 2, this.currentPage + 2)
},
/**
* Get the last page (or page count, it's the same).
*
* @return {Number}
*/
getLastPage () {
return Math.ceil(this.total / this.perPage)
},
/**
* Build page range.
*
* @param {Number} start
* @param {Number} end
* @return {Array}
*/
getPageRange (start, end) {
return _.range(start, end + 1)
},
/**
* Navigate to a specific page number.
*
* @param {Number} page
*/
goToPage (page) {
// Make sure to keep query parameters... needed to maintain the search between pages.
let query = _.clone(this.$route.query)
// Preserve selected page in search query. Useful to share a specific result page.
query.page = page
// Update the route
this.$router.push({
query
})
}
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment