文章列表分页

添加分页组件

在 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>

我们分两步来讲一下切换分页的逻辑:

  1. 基于 $route.query.page 返回 currentPage 的值,然后使用 currentPage 设置当前页和获取对应的文章;
  2. 点击分页的时候,调用 changePage 方法,跳转到类似 /topics?filter=default&page=2 的地址,$route.query.page 改变,重复上一步;
posted @ 2018-07-17 16:02  前端极客  阅读(677)  评论(0编辑  收藏  举报