前言
上篇文章中,已經使用vue實現前端分頁效果,這篇文章我們單獨將分頁抽離出來實現一個分頁組件
先看實現效果圖

代碼實現
按照慣例,我們在凍手實現的時候還是先想一想vue實現組件的思路
1、需要提前設定哪些參數需要暴露出來給父組件傳遞
<Paging
:name="name"
@change="onPageChange"
:page-size="size"
:total="total"
layout="jumper,total"
:current-page="curPage"
/>
方法及參數說明
屬性
page-size 每頁顯示條目個數
total 總條目數
current-page 當前頁數
layout 布局 默認不顯示 jumper,total
事件
change 當前頁改變時觸發
2、再一個就是涉及到的父子組件通信
這里主要通過props向子組件傳遞參數
在子組件中使用emit自定義事件返回數據給父組件
a.字符串數組形式props
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
或者指定每個prop的值類型
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object
}
b.props驗證
props: {
// 基礎的類型檢查 (`null` 匹配任何類型)
propA: Number,
// 多個可能的類型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 帶有默認值的數字
propD: {
type: Number,
default: 100
},
// 帶有默認值的對象
propE: {
type: Object,
// 對象或數組默認值必須從一個工廠函數獲取
default: function () {
return { message: 'hello' }
}
},
// 自定義驗證函數
propF: {
validator: function (value) {
// 這個值必須匹配下列字符串中的一個
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
使用props傳遞數據給子組件 ,子組件主要有三種形式來接收到父組件傳遞過來的參數
props字符串數組、指定每個prop值類型以及props驗證,通常我們會使用props驗證
分析完之后,接下來我們可以凍手實現了
1、這里我們用vue-cli先創建一個vue項目
安裝vue-cli
$npm install -g vue-cli
創建vue項目
$vue init webpack my-project
項目運行
$cd my-project
$npm run dev
2、在components文件下創建一個Paging組件
<template>
<div class="paging clearfix">
<div class="page-size fl" v-if="isShowTotal">共{{total}}條</div>
<ul class="page-list fl clearfix">
<li @click="changePage(currentPage-1)">上一頁</li>
<li :class="{'active':currentPage==item.val}" v-for="item in pagelist" v-text="item.text" @click="changePage(item.val)">1</li>
<li @click="changePage(currentPage+1)">下一頁</li>
</ul>
<div class="page-jump fl" v-if="isShowJumper">
前往<input class="input" type="text" v-model="toPage" @keydown="submit(toPage,$event)">頁
<!-- <button @click="changePage(toPage)">確定</button> -->
</div>
</div>
</template>
<script>
export default {
name: 'Paging',
// props:[
// 'name'
// ],
// prop驗證
props:{
name:String,
pageSize: {
type: Number,
default: 10
},
total: {
type: Number,
default: 0
},
currentPage: {
type: Number,
default: 1
},
layout:{
type: String
}
},
data () {
return {
isShowJumper:false,
isShowTotal:false,
toPage:'',//跳轉到x頁
pageGroup:10//可見分頁數量 默認10個分頁數
}
},
created: function () {
console.log('created');
this.isShowTotal = this.layout.indexOf('total')!==-1;
this.isShowJumper = this.layout.indexOf('jumper')!==-1;
},
mounted: function () {
console.log('mounted',this.layout);
},
computed:{
totalPage:function(){
return Math.ceil(this.total / this.pageSize)
},
pagelist:function(){
var list = [];
var count = Math.floor(this.pageGroup/2), center = this.currentPage;
var left = 1,right = this.totalPage;
if(this.totalPage>this.pageGroup){
if(this.currentPage>count+1){
if(this.currentPage < this.totalPage - count){
left = this.currentPage - count;
right = this.currentPage + count-1;
}else{
left = this.totalPage - this.pageGroup+1;
}
}else{
right = this.pageGroup;
}
}
// 遍歷添加到數組里
while(left<=right){
list.push({
text:left,
val:left
});
left++;
}
return list;
}
},
methods:{
// 回車事件
submit(toPage,e){
// console.log('e.keyCode',toPage,e.keyCode)
// key.Code === 13表示回車鍵
if(e.keyCode === 13){
//邏輯處理
this.changePage(toPage);
}
},
changePage:function(idx){
if(idx!=this.currentPage && idx>0 && idx<=this.totalPage){
// 觸發父組件事件 pageChange會轉換成小寫pagechange
this.$emit('change',{curPage:Number(idx)});
}
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
*{
padding: 0;
margin: 0;
}
.fl{
float: left;
}
.clearfix:after{
display: block;
content: '';
clear: both;
}
.page-size{
height: 26px;
line-height: 26px;
}
.page-list{
}
.page-jump{
height: 26px;
line-height: 26px;
margin-left: 20px;
}
.page-jump .input{
width: 32px;
padding: 4px 2px;
border-radius: 2px;
border: 1px solid #dcdfe6;
margin: 0 4px;
}
ul{
list-style: none;
}
ul li{
float: left;
color: #606266;
background: #f4f4f5;
padding: 2px 8px;
cursor: pointer;
border-radius: 2px;
margin: 0 5px;
}
ul>li.active{
background: #409eff;
color:#fff;
}
</style>
3、在父組件中引入並使用組件
<template>
<div>
<!-- 分頁組件 -->
<Paging
:name="name"
@change="onPageChange"
:page-size="size"
:total="total"
layout="jumper,total"
:current-page="curPage"
/>
</div>
</template>
<!--
Paging屬性
page-size 每頁顯示條目個數
total 總條目數
current-page 當前頁數
layout 布局 默認不顯示 jumper,total
Paging事件
change 當前頁改變時觸發
-->
<script>
import Paging from '@/components/Paging';
export default {
name: 'Index',
components:{
Paging
},
data () {
return {
msg: 'hello',
name:'阿健a',
size:10,
total:201,
curPage:1
}
},
methods:{
onPageChange:function(page){
this.curPage = page.curPage;
}
}
}
</script>
遇到的問題
1、在子組件中修改currentPage時報錯
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders
在使用組件時,傳入的prop,被組件內部又做了一次修改
避免直接修改prop,因為當父組件重新呈現時,值將被覆蓋
changePage:function(idx){
if(idx!=this.currentPage && idx>0 && idx<=this.totalPage){
this.currentPage = idx;
// 觸發父組件事件 pageChange會轉換成小寫pagechange
this.$emit('change');
}
}
解決
修改代碼,通過emit傳遞curPage給父組件,讓父組件修改
changePage:function(idx){
if(idx!=this.currentPage && idx>0 && idx<=this.totalPage){
// 觸發父組件事件 pageChange會轉換成小寫pagechange
this.$emit('change',{curPage:idx});
}
}
父組件監聽事件更新curPage
onPageChange:function(page){
this.curPage = page.curPage;
}
最后
以上就是分頁組件的整個實現過程 ,其實只要搞清楚父子組件是如何傳參的,以及我們實現一個組件需要暴露哪些參數給父組件,整個實現過程還是不難的
