Vue Paging Example

An example of wiring up a paging section using Vue.js

by Jake

HTML

<div id="app">
    <p style="text-align:center">
        Show
        <input v-model="perPage" type="text"> items per Page
    </p>
    <div :class="['paging',pagingClass]">
        <a href="#" :class="['prev-button',prevButtonClass]" @click.prevent="prevPage()">Previous</a>
        <p>Page
            <select name="page" v-model="pageNum">
                <option v-for="(page,key) in totalPages" :value="page">{{ page }} </option>
            </select>
            of {{ totalPages }}</p>
        <a href="#" :class="['next-button',nextButtonClass]" @click.prevent="nextPage()">Next</a>
    </div>

    <div class="output">Show items {{ firstItemOnPage }} through {{ lastItemOnPage }}.</div>


    <br>
    <br>
    <br>
    <input type="text" v-model="itemCount"> (total items)
</div>

SCSS

input[type="text"] {
  width:3.4em;
}
.paging {
	display:         flex;
	justify-content: center;
	align-items: center;
	padding: .8em;
  
  &.disabledPaging {
    opacity: .2;
  }

	a, p {
		display: block;
		margin: .2em;
	}

	a {
		background: hsl(210,90%,37%);
		color: #fff;
		border-radius: 3px;
		padding: .5em 1.3em;
		text-decoration: none;
		&:hover {
			box-shadow: 0 0 3em hsla(0,0%,0%,.2) inset;
			color: white;
		}
	}

	a.disabled {
		pointer-events: none;
		opacity: .1;
	}

	a.prev-button:before {
		content: '< ';
	}
	a.next-button:after {
		content: ' >';
	}
}

.output {
  background: white;
  padding: 1em;
  font-size: 1.1em;
}

JavaScript

new Vue({
    el: '#app',
    
    
    data: {
        itemCount: 857,
        pageNum: 1,
        perPage: 10
    },
    
    
    computed: {
        totalPages() {
                return Math.ceil(this.itemCount / this.perPage);
            },
            prevPageNumber() {
                if (this.totalPages < 2 || this.pageNum < 2)
                    return false;
                return this.pageNum - 1 || 1;
            },
            nextPageNumber() {
                let pageNum;
                if (this.totalPages < 2)
                    pageNum = 1;
                if (this.pageNum <= this.totalPages)
                    pageNum = this.pageNum + 1;
                // -- validate 
                if (pageNum > this.totalPages)
                    return false;
                return pageNum;
            },
            prevButtonClass() {
                if (this.pageNum < 2)
                    return 'disabled';
            },
            nextButtonClass() {
                if (this.pageNum >= this.totalPages)
                    return 'disabled';
            },
            pagingClass() {
                if (this.totalPages < 2)
                    return "disabledPaging";
            },
            firstItemOnPage() {
                return parseInt((this.pageNum - 1) * this.perPage + 1);
            },
            lastItemOnPage() {
                var perPage = parseInt(this.perPage);
                return ((this.pageNum - 1) * perPage) + perPage;
            }
    },
    watch: {
        totalPages() {
            if (this.totalPages === 0) {
                this.pageNum = 1;
                return;
            }
            if (this.pageNum > this.totalPages) {
                this.pageNum = this.totalPages;
            }
        }
    },
    methods: {
        nextPage() {
                if (this.pageNum >= this.totalPages)
                    return false;
                this.pageNum++;
            },
            prevPage() {
            ...