封装分页器


1. 前言

分页器基本上是任何网站必须要有的一个组件,为什么需要分页器,当后台传入了大量的数据,那么在前端拿到数据,如果直接展示很有可能或造成卡顿,同时消耗过多的内存,给用户带来的浏览效果就不好。所以,分页器的使用可以一次性只展示部分数据,用户可以非常方便的跳转不同的页面来访问内容。虽然现在很多的UI库都有这个组件,使用也非常的方便,但是我们也应该要知道,怎么手写一个分页器。

2. 准备

先搭建一个静态的分页器。效果如下图。

<template><div class="pagination"><button>上一页</button><button>1</button><button>...</button><button>4</button><button>5</button><button>6</button><button>7</button><button>...</button><button>11</button><button>下一页</button><button style="margin-left: 30px">共 11 条</button></div>
</template><script>
export default {// eslint-disable-next-line vue/multi-word-component-namesname: 'Pagination'
}
</script><style lang="less" scoped>
.pagination {text-align: center;button {margin: 0 5px;background-color: #f4f4f5;color: #606266;outline: none;border-radius: 2px;padding: 0 4px;vertical-align: top;display: inline-block;font-size: 13px;min-width: 35.5px;height: 28px;line-height: 28px;cursor: pointer;box-sizing: border-box;text-align: center;border: 0;&[disabled] {color: #c0c4cc;cursor: not-allowed;}&.active {cursor: not-allowed;background-color: #409eff;color: #fff;}}
}
.active {background: skyblue;
}
</style>

​ 既然是封装组件,那么就要考虑当其他组件在使用时,需要传递什么参数,这就要去思考分页器需要些什么。首先,必须知道当前的页数,是第一页还是第二页;其次,每一页需要展示多少数据;再次,一共有多少条数据;最后:分页器连续的页面个数(看上面的图片,页面之间会有省略号,意思就是如果我设置连续的页数是3,那么如果有10页,当前是第5页,页面中显示的就是应该是 1 … 4 5 6… 10,其余的就不展示,用省略号代替)

​ 综上,我们需要其他组件(父组件)在使用传递四个参数

// pageNo: 当前的页数,pageSize:每一页展示数据的量 total:总数 continues:连续的页数
<Pagination :pageNo="2" :pageSize="3" :total="91" :continues="3">// 在pagination中接收参数
export default {// eslint-disable-next-line vue/multi-word-component-namesname: 'Pagination',props: ['pageNo', 'pageSize', 'total', 'continues'],
}

那么到这儿,前期的准备就差不多了,下面我们就要开始书写里面的逻辑。

3. 逻辑设计

在我们拿到父组件传递过来的数据,我们需要计算两个属性的值,分别是:总共多少页和连续页面的起始数字和结束数字。下面我先计算总共多少页。

// 这是我在app.vue中设置的默认值
<Pagination :pageNo="1" :pageSize="5" :total="90" :continues="3"></Pagination>// pagination.vue
// 计算一共有多少页,用总的页数/每页展示的数据量,因为结果可能为小数,所有这里向上取整
totalPage() {return Math.ceil(this.total / this.pageSize);
}// 绑定数据
<button style="margin-left: 30px">共 {{totalPage}} 页</button>
<button style="margin-left: 30px">共 {{total}} 条</button>

效果展示

第二步,就是计算连续页面的起始位置。

 //计算出连续的页码的起始数字与结束数字[连续页码的数字:至少是3]startNumAndEndNum() {const { continues, pageNo, totalPage } = this//先定义两个变量存储起始数字与结束数字let start = 0,end = 0//连续页码数字3【就是至少3页】,如果出现不正常的现象【就是不够3页】//不正常现象【总页数没有连续页码多】if (continues > totalPage) {start = 1end = totalPage} else {//正常现象【连续页码3,但是你的总页数一定是大于3的】//起始数字start = pageNo - parseInt(continues / 2)//结束数字end = pageNo + parseInt(continues / 2)//把出现不正常的现象【start数字出现0|负数】纠正if (start < 1) {start = 1end = continues}//把出现不正常的现象[end数字大于总页码]纠正if (end > totalPage) {end = totalPagestart = totalPage - continues + 1}}return { start, end }}

到这里,分页器两大主功能就写好了,接下来处理页面展示的页码。由于每次点击这些页码按钮,我们都必须知道当前是第几页,或者又比如点击上一页,当前的页面数要减一,所有我们需要在父组件中设置一个函数来把当前的页数传递给pagonation组件。

<Pagination :pageNo="page" :pageSize="5" :total="90" :continues="3" @getPageNo="getPageNo"></Pagination>
<script>
import Pagination from "@/components/Pagination.vue"
export default {name: 'App',data() {return {// 初始化页数page:1}},components: {Pagination},methods: {getPageNo(page) {this.page = page;}}
}
</script>

整体把分页器分成三个部分,包括最左边的上一页、起始页1、和…,中间部分的连续页面数,最右边的…,尾页,下一页,总页数,总数据数。

 <!-- 左 --><!-- 这里需要判断,当目前的页数是第一页时,就禁用该按钮,否则会出现错误,点击的时候,就调用父组件的函数,让当前选中的页数减一 --><button :disabled="pageNo == 1" @click="$emit('getPageNo', pageNo - 1)">上一页</button><!-- 这里要注意,之所以要判断是是否展示该按钮是因为循环的时候是从1开始的,如果不加以判断,当startNumAndEndNum.start = 1时页面就会出现两个按钮1 --><buttonv-if="startNumAndEndNum.start > 1"@click="$emit('getPageNo', 1)":class="{ active: pageNo == 1 }">1</button><!--  只有当连续页数的起始值大于2,才需要显示...--><button v-if="startNumAndEndNum.start > 2">···</button><!-- 中间 --><!-- 通过循环在连续页面的限制先展示相应的按钮页码,只有大于startNumAndEndNum.start的页面才会展示 --><!-- eslint-disable-next-line vue/no-use-v-if-with-v-for --><button v-for="(page, index) in startNumAndEndNum.end" :key="index" v-if="page >= startNumAndEndNum.start" @click="$emit('getPageNo', page)" :class="{ active: pageNo == page }">{{ page }}</button><!-- 右 --><!--  只有当连续页数的终止值小于页面总数减一时,才需要显示...--><button v-if="startNumAndEndNum.end < totalPage - 1">···</button><!--  这里也和按钮1一样,如果连续页面的终止值小于总页数就展示,否则会出现两个尾页按钮--><buttonv-if="startNumAndEndNum.end < totalPage"@click="$emit('getPageNo', totalPage)":class="{ active: pageNo == totalPage }">{{ totalPage }}</button><!-- 点击时页码数减一,当前是最后一页时静止 --><button:disabled="pageNo == totalPage"@click="$emit('getPageNo', pageNo + 1)">下一页</button><button style="margin-left: 30px">共 {{ total }} 条</button>

看看效果

4 全部代码

父组件

<template><div id="app"><h1>我是app</h1><Pagination :pageNo="page" :pageSize="5" :total="90" :continues="3" @getPageNo="getPageNo"></Pagination></div>
</template><script>
import Pagination from "@/components/Pagination.vue"
export default {name: 'App',data() {return {// 初始化页数page:1}},components: {Pagination},methods: {getPageNo(page) {this.page = page;}}
}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
</style>

Pagination

<template><div class="pagination"><!-- 上 --><button :disabled="pageNo == 1" @click="$emit('getPageNo', pageNo - 1)">上一页</button><buttonv-if="startNumAndEndNum.start > 1"@click="$emit('getPageNo', 1)":class="{ active: pageNo == 1 }">1</button><button v-if="startNumAndEndNum.start > 2">···</button><!-- 中间部分 --><!-- eslint-disable-next-line vue/no-use-v-if-with-v-for --><button v-for="(page, index) in startNumAndEndNum.end" :key="index" v-if="page >= startNumAndEndNum.start" @click="$emit('getPageNo', page)" :class="{ active: pageNo == page }">{{ page }}</button><!-- 下 --><button v-if="startNumAndEndNum.end < totalPage - 1">···</button><buttonv-if="startNumAndEndNum.end < totalPage"@click="$emit('getPageNo', totalPage)":class="{ active: pageNo == totalPage }">{{ totalPage }}</button><button:disabled="pageNo == totalPage"@click="$emit('getPageNo', pageNo + 1)">下一页</button><button style="margin-left: 30px">共 {{ total }} 条</button></div>
</template><script>
export default {// eslint-disable-next-line vue/multi-word-component-namesname: 'Pagination',props: ['pageNo', 'pageSize', 'total', 'continues'],computed: {// 计算一共有多少页,用总的页数/每页展示的数据量,因为结果可能为小数,所有这里向上取整totalPage() {return Math.ceil(this.total / this.pageSize);},//计算出连续的页码的起始数字与结束数字[连续页码的数字:至少是3]startNumAndEndNum() {const { continues, pageNo, totalPage } = this//先定义两个变量存储起始数字与结束数字let start = 0,end = 0//连续页码数字3【就是至少3页】,如果出现不正常的现象【就是不够3页】//不正常现象【总页数没有连续页码多】if (continues > totalPage) {start = 1end = totalPage} else {//正常现象【连续页码3,但是你的总页数一定是大于3的】//起始数字start = pageNo - parseInt(continues / 2)//结束数字end = pageNo + parseInt(continues / 2)//把出现不正常的现象【start数字出现0|负数】纠正if (start < 1) {start = 1end = continues}//把出现不正常的现象[end数字大于总页码]纠正if (end > totalPage) {end = totalPagestart = totalPage - continues + 1}}return { start, end }}}
}
</script><style lang="less" scoped>
.pagination {text-align: center;button {margin: 0 5px;background-color: #f4f4f5;color: #606266;outline: none;border-radius: 2px;padding: 0 4px;vertical-align: top;display: inline-block;font-size: 13px;min-width: 35.5px;height: 28px;line-height: 28px;cursor: pointer;box-sizing: border-box;text-align: center;border: 0;&[disabled] {color: #c0c4cc;cursor: not-allowed;}&.active {cursor: not-allowed;background-color: #409eff;color: #fff;}}
}
.active {background: skyblue;
}
</style>

手写一个简单的分页器相关推荐

  1. 手写一个简单的IOC容器

    手写一个简单的IOC容器 原文 http://localhost:4000/2020/02/25/SSM/spring/%E6%89%8B%E5%86%99%E4%B8%80%E4%B8%AA%E5% ...

  2. jquery手写轮播图_用jQuery如何手写一个简单的轮播图?(附代码)

    用jQuery如何手写一个简单的轮播图?下面本篇文章通过代码示例来给大家介绍一下.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 用 jQuery 手写轮播图 先上个效果截图: 主要 ...

  3. 怎么手写一个简单的List集合

    List集合 手写一个简单的List集合为自己调用并不是特别难,只需要定义一个集合接口去提供所有方法的定义如下代码 : package com.myself.util; /*** * @author ...

  4. 手写一个简单的HashMap,搞定挑剔面试官

    作者:编程十二 链接:https://www.jianshu.com/p/1be0e957baf2 前言 今天去面试啊,聊得差不多的时候面试官突然问我会手写HashMap吗?这我哪能怂啊,好死不死的面 ...

  5. 手写一个简单的线程池MyThreadPool

    说明 手写的一个简单的线程池,旨在帮助了解线程池的工作原理. 核心内容 核心工作线程 任务阻塞队列 定义一个内部类去实现核心工作线程 /*** 内部类:工作的核心线程*/private final c ...

  6. 深入了解Vue 2响应式原理,并手写一个简单的Vue

    1. Vue 2的响应式原理 Vue.js 一个核心思想是数据驱动.所谓数据驱动是指视图是由数据驱动生成的,对视图的修改,不会直接操作 DOM,而是通过修改数据.vue.js里面只需要改变数据,Vue ...

  7. 小白前端之路:手写一个简单的vue-router这几年,好像过的好快,怀念我的大学生活。 - 连某人 大三实习生,之前写过简单MVVM框架、简单的vuex、但是看了vue-router的源码(看了

    这几年,好像过的好快,怀念我的大学生活. 连某人 大三实习生,之前写过简单MVVM框架.简单的vuex.但是看了vue-router的源码(看了大概)之后就没有写,趁着周末不用工作(大三趁着不开学出来 ...

  8. 手写一个简单rpc框架(一)

    扑街前言:前面说了netty的基本运用.Java的NIO等一系列的知识,这些知识已经可以做一个简单的rpc框架,本篇和下篇我们一起了解一个怎么完成一个rpc框架,当然个只是为了更好的了解rpc框架的基 ...

  9. Java 手写一个简单计算器(1)

    用java的awt和swing实现了界面, 结构比较简单,用GridLayout布局实现 文本框+3行按钮+3行按钮: 按钮用字符串数组和for循环 后两个用JPanel存放 然后加到框架中即可 由于 ...

最新文章

  1. python第三方库是什么意思-Python最强大的第三方库,你有必要了解一下!
  2. EL之RF(RFR):利用RandomForestRegressor对回归问题(实数值评分预测)建模(调2参)
  3. C# 检测dll的新版本号方法
  4. ecplice中class.forname一直报错_英雄联盟LOL闪退,弹出吉格斯报错BUGSPLAT
  5. python中什么是关键字参数_如何使用python语言中函数的关键字参数的用法
  6. 牛客16585 统计单词数
  7. python房地产爬虫_房产中介网站爬虫实战(Python BS4+多线程)(一)
  8. MYSQL多线程插入操作
  9. python动态图表变化_Python数据可视化 pyecharts实现各种统计图表过程详解
  10. Google被骂成筛子
  11. Could not connect to any servers in your MongoDB Atlas cluster. One common reason is that you‘re try
  12. noi linux 默认密码,安装NOI Linux
  13. 通过对arcsinx的泰勒展开式求圆周率值
  14. java不使用科学计数法_java不用科学计数法
  15. 计算机音译英语单词,汉语谐音英文单词
  16. 小程序发送邮件,小程序云开发使用云函数发送邮件
  17. 192.168.8.1手机登陆_192.168.8.1登录入口上网设置
  18. 数据结构相关重点(个人总结)
  19. 开山ORC螺杆膨胀发电机
  20. 关于储备(应急储备、管理储备、储备分析)的总结讨论

热门文章

  1. django自带邮件模块实现用户注册激活邮件发送
  2. clickonce 部署ClickOnce应用程序时出错-清单中的引用与下载的程序集的标识不匹配
  3. 抖音康辉机器人_康辉录抖音,没想到央视主播们这么会玩!
  4. 关于win10系统(客户机)无法添加网络共享打印机的解决办法(提示信息:操作失败,错误为0X0000011B)
  5. DCM(DICOM)医学影像文件格式详解
  6. mysql多表关联 group by + order by 优化
  7. Filter Listener
  8. mysql 增删改查常用命令 收藏
  9. H - 遇到百分之百的女孩
  10. oracle命令解锁用户,在命令行下进行Oracle用户解锁的语句