Vue.js - Simple Pagination Example
Example built with Vue 2.6.10
Other versions available:
- Vue: Vue + Node
- React: React, React + Node
- Angular: Angular 10, 9, 8, 2/5, Angular + Node
- AngularJS: AngularJS
- ASP.NET: Razor Pages, ASP.NET MVC
This is a simple example of how to implement client-side pagination in Vue.js.
The example contains a hard coded array of 150 objects split into 15 pages to demonstrate how the pagination component works.
The project is available on GitHub at https://github.com/cornflourblue/vue-pagination-example.
Here it is in action: (See on CodeSandbox at https://codesandbox.io/s/vuejs-pagination-tutorial-example-robvf)
Running the Vue.js Pagination Example Locally
- Install NodeJS and NPM from https://nodejs.org.
- Download or clone the tutorial project source code from https://github.com/cornflourblue/vue-pagination-example.
- Install all required npm packages by running the
npm install
command in the project root folder (where the package.json is located). - Start the Vue.js app by running
npm start
in the project root folder, this will build the app with webpack and automatically launch it in a browser on the URLhttp://localhost:8080
.
Vue.js Pagination Component
Pagination is implemented with the <jw-pagination>
component that comes with the jw-vue-pagination
package available on npm.
Installation
Install the Vue pagination component with the command npm install jw-vue-pagination
.
Integration with your Vue.js app
Import the JwPagination
component from the 'jw-vue-pagination'
package and register it globally within your Vue application by calling Vue.component('jw-pagination', JwPagination);
The first parameter is the component name, it defines the custom tag used to add the component to other components, in this case it will be with the tag <jw-pagination></jw-pagination>
. The second parameter points to the actual Vue component.
Global registration makes the Vue component available to all other components within the Vue application, it's also possible to register components locally, for more info see https://vuejs.org/v2/guide/components-registration.html.
This is the main Vue entry file (/src/index.js
) from the example, the pagination component is imported and registered globally on lines 6-7
.
import Vue from "vue";
import App from "./app/App";
// register jw pagination component globally
import JwPagination from 'jw-vue-pagination';
Vue.component('jw-pagination', JwPagination);
new Vue({
el: "#app",
render: h => h(App)
});
Usage
There are 2 required properties for using the Vue.js pagination component:
- items - the array of items to be paged
- changePage - an event listener function for handling the
changePage
event
There are also a few optional properties:
- pageSize - the number of items displayed on each page (defaults to 10)
- maxPages - the max number of page links to display in the pagination nav (defaults to 10)
- initialPage - the initial page to display (defaults to 1)
Example Vue.js Component with Pagination
This is the App component (/src/app/App.vue
) from the example. The template renders the current page of items using the v-for
Vue directive on line 5
, and includes the pagination component (<jw-pagination ...>
) on line 8
.
The component logic creates a hardcoded array of exampleItems
to be paged and updates the current page of items in the onChangePage()
method.
<template>
<div class="card text-center m-3">
<h3 class="card-header">Vue.js Pagination Tutorial & Example</h3>
<div class="card-body">
<div v-for="item in pageOfItems" :key="item.id">{{item.name}}</div>
</div>
<div class="card-footer pb-0 pt-3">
<jw-pagination :items="exampleItems" @changePage="onChangePage"></jw-pagination>
</div>
</div>
</template>
<script>
// an example array of items to be paged
const exampleItems = [...Array(150).keys()].map(i => ({ id: (i+1), name: 'Item ' + (i+1) }));
export default {
data() {
return {
exampleItems,
pageOfItems: []
};
},
methods: {
onChangePage(pageOfItems) {
// update page of items
this.pageOfItems = pageOfItems;
}
}
};
</script>
Styling the Pagination Component
The Vue pagination component comes with some very basic default styles. To use your own custom styles I'd recommend disabling the default styles by adding the property :disableDefaultStyles="true"
to the <jw-pagination>
component, then adding custom styles in your css with the following css selectors:
- .pagination - Pagination component container (
ul
element) - .pagination li - All list items in the pagination component
- .pagination li a - All pagination links including first, last, previous and next
- .pagination li.page-number - All page numbers (1, 2, 3 etc) pagination elements
- .pagination li.first - The 'First' pagination element
- .pagination li.last - The 'Last' pagination element
- .pagination li.previous - The 'Previous' pagination element
- .pagination li.next - The 'Next' pagination element
Note: you can also plug in Bootstrap CSS (3.x or 4.x), that's what is used in the example.
If you prefer you can also override or extend the default styles (instead of disabling them) by passing a custom styles object to the jw-pagination component like this:
<template>
...
<jw-pagination :items="exampleItems" @changePage="onChangePage" :styles="customStyles"></jw-pagination>
...
</template>
<script>
...
const customStyles = {
ul: {
border: '2px solid red'
},
li: {
display: 'inline-block',
border: '2px dotted green'
},
a: {
color: 'blue'
}
};
export default {
data() {
return {
...
customStyles
};
},
...
};
</script>
Custom labels for First, Last, Next & Previous pagination buttons
You can use custom labels for the First, Last, Next & Previous buttons by passing a labels object to the jw-pagination component like this:
<template>
...
<jw-pagination :items="exampleItems" @changePage="onChangePage" :labels="customLabels"></jw-pagination>
...
</template>
<script>
const customLabels = {
first: '<<',
last: '>>',
previous: '<',
next: '>'
};
export default {
data() {
return {
...
customLabels
};
},
...
};
</script>
Hiding pagination buttons
To hide any of the buttons you can simply set them to display: none;
using the css selectors described above.
Further Customisation of the Vue.js Pagination Component
If you want to make further customisations such as changing the HTML template of the component, I'd recommend just copying the pagination component code into your own custom Vue component, it's a fairly simple component and this approach will give you complete flexibility to make any changes you like.
To use this approach you need to install the jw-paginate
package from npm with the command npm install jw-paginate
. The jw-paginate
package contains the pagination logic used to paginate any array or list of items. For more info about the pagination logic see this post.
This is the complete pagination component code, it's also available here on GitHub.
<template>
<ul v-if="pager.pages && pager.pages.length" class="pagination" :style="ulStyles">
<li class="page-item first" :class="{'disabled': pager.currentPage === 1}" :style="liStyles">
<a class="page-link" @click="setPage(1)" :style="aStyles">{{labels.first}}</a>
</li>
<li class="page-item previous" :class="{'disabled': pager.currentPage === 1}" :style="liStyles">
<a class="page-link" @click="setPage(pager.currentPage - 1)" :style="aStyles">{{labels.previous}}</a>
</li>
<li v-for="page in pager.pages" :key="page" class="page-item page-number" :class="{'active': pager.currentPage === page}" :style="liStyles">
<a class="page-link" @click="setPage(page)" :style="aStyles">{{page}}</a>
</li>
<li class="page-item next" :class="{'disabled': pager.currentPage === pager.totalPages}" :style="liStyles">
<a class="page-link" @click="setPage(pager.currentPage + 1)" :style="aStyles">{{labels.next}}</a>
</li>
<li class="page-item last" :class="{'disabled': pager.currentPage === pager.totalPages}" :style="liStyles">
<a class="page-link" @click="setPage(pager.totalPages)" :style="aStyles">{{labels.last}}</a>
</li>
</ul>
</template>
<script>
import paginate from 'jw-paginate';
const defaultLabels = {
first: 'First',
last: 'Last',
previous: 'Previous',
next: 'Next'
};
const defaultStyles = {
ul: {
margin: 0,
padding: 0,
display: 'inline-block'
},
li: {
listStyle: 'none',
display: 'inline',
textAlign: 'center'
},
a: {
cursor: 'pointer',
padding: '6px 12px',
display: 'block',
float: 'left'
}
};
export default {
props: {
items: {
type: Array,
required: true
},
initialPage: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 10
},
maxPages: {
type: Number,
default: 10
},
labels: {
type: Object,
default: () => defaultLabels
},
styles: {
type: Object
},
disableDefaultStyles: {
type: Boolean,
default: false
}
},
data () {
return {
pager: {},
ulStyles: {},
liStyles: {},
aStyles: {}
}
},
created () {
if (!this.$listeners.changePage) {
throw 'Missing required event listener: "changePage"';
}
// set default styles unless disabled
if (!this.disableDefaultStyles) {
this.ulStyles = defaultStyles.ul;
this.liStyles = defaultStyles.li;
this.aStyles = defaultStyles.a;
}
// merge custom styles with default styles
if (this.styles) {
this.ulStyles = { ...this.ulStyles, ...this.styles.ul };
this.liStyles = { ...this.liStyles, ...this.styles.li };
this.aStyles = { ...this.aStyles, ...this.styles.a };
}
// set page if items array isn't empty
if (this.items && this.items.length) {
this.setPage(this.initialPage);
}
},
methods: {
setPage(page) {
const { items, pageSize, maxPages } = this;
// get new pager object for specified page
const pager = paginate(items.length, page, pageSize, maxPages);
// get new page of items from items array
const pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);
// update pager
this.pager = pager;
// emit change page event to parent component
this.$emit('changePage', pageOfItems);
}
}
}
</script>
Need Some Vue Help?
Search fiverr for freelance Vue developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!