添加分页组件
在 src/components
下新建 Pagination.vue
文件,复制贴入以下代码:
src/components/Pagination.vue
1 <template> 2 <ul v-if="totalPage > 1" class="pagination"> 3 <li :class="{ disabled: internalCurrentPage === 1 }"> 4 <a href="javascript:;" @click="changePage(internalCurrentPage - 1)">«</a> 5 </li> 6 <li v-for="n in totalPage" :class="{ active: internalCurrentPage === n }"> 7 <a href="javascript:;" @click="changePage(n)">{{ n }}</a> 8 </li> 9 <li :class="{ disabled: internalCurrentPage === totalPage }"> 10 <a href="javascript:;" @click="changePage(internalCurrentPage + 1)">»</a> 11 </li> 12 </ul> 13 </template> 14 15 <script> 16 export default { 17 name: 'Pagination', 18 props: { 19 // 当前页 20 currentPage: { 21 type: Number, 22 default: 1 23 }, 24 // 数据总数 25 total: { 26 type: Number, 27 required: true 28 }, 29 // 每页条数 30 pageSize: { 31 type: Number, 32 default: 10, 33 validator: value => value > 0 34 }, 35 // 当前页改变后的回调 36 onPageChange: { 37 type: Function, 38 default: () => {} 39 } 40 }, 41 data() { 42 return { 43 // 组件内的当前页 44 internalCurrentPage: 1 45 } 46 }, 47 computed: { 48 // 总页数 49 totalPage() { 50 return Math.ceil(this.total / this.pageSize) 51 } 52 }, 53 watch: { 54 currentPage: { 55 immediate: true, 56 handler(page) { 57 // 更新组件内的当前页,为父组件上 currentPage 的当前值 58 this.internalCurrentPage = page 59 } 60 } 61 }, 62 methods: { 63 changePage(page) { 64 if (page === this.internalCurrentPage || page < 1 || page > this.totalPage) return 65 // 点击的不是当前页时,触发 onPageChange 回调 66 this.onPageChange(page) 67 } 68 } 69 } 70 </script> 71 72 <style scoped> 73 74 </style>
注册分页组件
打开 src/components/index.js
文件,复制以下代码进行替换(注释部分是涉及的修改):
src/components/index.js
1 import Vue from 'vue' 2 import Message from './Message' 3 import Modal from './Modal' 4 // 引入 Pagination.vue 的默认值 5 import Pagination from './Pagination' 6 7 const components = { 8 Message, 9 Modal, 10 // 添加 Pagination 以便在循环中进行注册 11 Pagination 12 } 13 14 for (const [key, value] of Object.entries(components)) { 15 Vue.component(key, value) 16 }
修改测试数据
打开 src/main.js
文件,查找 ...mockArticles(10)
,修改它的数量:
src/main.js
store.commit('UPDATE_ARTICLES', [...userArticles, ...mockArticles(60)])
使用分页组件
1、打开 src/views/Home.vue
文件,复制以下代码替换原 <script>
(注释部分是涉及的修改):
src/views/Home.vue
1 <script> 2 import { mapState } from 'vuex' 3 4 export default { 5 name: 'Home', 6 data() { 7 return { 8 msg: '', 9 msgType: '', 10 msgShow: false, 11 articles: [], 12 filter: 'default', 13 filters: [ 14 { filter: 'default', name: '活跃', title: '最后回复排序'}, 15 { filter: 'excellent', name: '精华', title: '只看加精的话题'}, 16 { filter: 'vote', name: '投票', title: '点赞数排序'}, 17 { filter: 'recent', name: '最近', title: '发布时间排序'}, 18 { filter: 'noreply', name: '零回复', title: '无人问津的话题'} 19 ], 20 total: 0, // 文章总数 21 pageSize: 10, // 每页条数 22 } 23 }, 24 beforeRouteEnter(to, from, next) { 25 const fromName = from.name 26 const logout = to.params.logout 27 28 next(vm => { 29 if (vm.$store.state.auth) { 30 switch (fromName) { 31 case 'Register': 32 vm.showMsg('注册成功') 33 break 34 case 'Login': 35 vm.showMsg('登录成功') 36 break 37 } 38 } else if (logout) { 39 vm.showMsg('操作成功') 40 } 41 42 vm.setDataByFilter(to.query.filter) 43 }) 44 }, 45 computed: { 46 ...mapState([ 47 'auth', 48 'user' 49 ]), 50 // 当前页,从查询参数 page 返回 51 currentPage() { 52 return parseInt(this.$route.query.page) || 1 53 } 54 }, 55 watch: { 56 auth(value) { 57 if (!value) { 58 this.showMsg('操作成功') 59 } 60 }, 61 '$route'(to) { 62 this.setDataByFilter(to.query.filter) 63 } 64 }, 65 methods: { 66 showMsg(msg, type = 'success') { 67 this.msg = msg 68 this.msgType = type 69 this.msgShow = true 70 }, 71 setDataByFilter(filter = 'default') { 72 // 每页条数 73 const pageSize = this.pageSize 74 // 当前页 75 const currentPage = this.currentPage 76 // 过滤后的所有文章 77 const allArticles = this.$store.getters.getArticlesByFilter(filter) 78 79 this.filter = filter 80 // 文章总数 81 this.total = allArticles.length 82 // 当前页的文章 83 this.articles = allArticles.slice(pageSize * (currentPage - 1), pageSize * currentPage) 84 }, 85 // 回调,组件的当前页改变时调用 86 changePage(page) { 87 // 在查询参数中混入 page,并跳转到该地址 88 // 混入部分等价于 Object.assign({}, this.$route.query, { page: page }) 89 this.$router.push({ query: { ...this.$route.query, page } }) 90 } 91 } 92 } 93 </script>
我们分两步来讲一下切换分页的逻辑:
- 基于
$route.query.page
返回currentPage
的值,然后使用currentPage
设置当前页和获取对应的文章; - 点击分页的时候,调用
changePage
方法,跳转到类似/topics?filter=default&page=2
的地址,$route.query.page
改变,重复上一步;