什么是Pagination分页组件?
在 B 端的 web 开发中,分页组件或者叫分页器,是较为常用的控件之一,通常配合表格或列表,实现数据量大的情况下,分页拆解数据的功能。
1.scrollTo和滚动视觉差
HTML DOM里面定义了scrollTo方法,用法:scrollTo(xpos,ypos),把内容滚动到当前的指定位置。但是这个充其量只能说是移动而不能说是滚动,似乎没有滑动的效果显示出来。好在JQuery提供了足够多方便的插件,其中一个就能够提供平滑滚动的功能
插件叫做jquery.scrollTo.js,当然前提是首先包含jquery的库。而且它自己里面已经封装的很好了,只需要简单的调用作用在标签上的函数就能够实现平滑的滚动,用起来非常的简便。就像下面这样:
$(function(){
$(".nav_pro").click(function(){
$.scrollTo('#pro',500);
});
$(".nav_news").click(function(){
$.scrollTo('#news',800);
});
$(".nav_ser").click(function(){
$.scrollTo('#ser',1000);
});
$(".nav_con").click(function(){
$.scrollTo('#con',1200);
});
$(".nav_job").click(function(){
$.scrollTo('#job',1500);
});
});
scrollTo的两个参数一个定义要滚动的元素对象,另一个是滚动所持续的时间,以毫秒计算。
平滑滚动只是这个插件可以实现的一个最基本的方法,可以考虑在这基础上继续去做其他的应用,比如展示文档,模拟PPT效果等等。
2.vue3使用vue-scrollto
安装vue-scrollto
npm install --save vue-scrollto
然后在main.js引入
const VueScrollTo = require('vue-scrollto');
app.use(VueScrollTo)
最后在对应页面使用即可
<div class="flexca broadside_item" v-scroll-to="'#element'">
<img src="@/assets/img/icon_41.png" alt="" />
<img class="msg" src="@/assets/img/icon_42.png" alt="" v-if="false" />
</div>
v-scroll-to后面为点击需要跳转到页面元素的位置;
'#element'可随意命名,元素的class名或id名
3.vue分页组件--封装:方法一(常用)
为什么封装?
分页功能使用场景较多,故考虑封装为全局组件
自己封装成本较低,需要什么功能就添加什么功能
相对使用现成组件库,自己封装代码体积可控
分页组件采用的element组件里的封装一下即可全局使用,方便快捷
采用的是element组件的扥也组件,需安装element依赖,具体如何安装就不多说了。
一、在utils新建scroll-to.js
scroll-to.js内容:
Math.easeInOutQuad = function(t, b, c, d) {
t /= d / 2
if (t < 1) {
return c / 2 * t * t + b
}
t--
return -c / 2 * (t * (t - 2) - 1) + b
}
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
var requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
})()
/**
* Because it's so fucking difficult to detect the scrolling element, just move them all
* @param {number} amount
*/
function move(amount) {
document.documentElement.scrollTop = amount
document.body.parentNode.scrollTop = amount
document.body.scrollTop = amount
}
function position() {
return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
}
/**
* @param {number} to
* @param {number} duration
* @param {Function} callback
*/
export function scrollTo(to, duration, callback) {
const start = position()
const change = to - start
const increment = 20
let currentTime = 0
duration = (typeof (duration) === 'undefined') ? 500 : duration
var animateScroll = function() {
// increment the time
currentTime += increment
// find the value with the quadratic in-out easing function
var val = Math.easeInOutQuad(currentTime, start, change, duration)
// move the document.body
move(val)
// do the animation unless its over
if (currentTime < duration) {
requestAnimFrame(animateScroll)
} else {
if (callback && typeof (callback) === 'function') {
// the animation is done so lets callback
callback()
}
}
}
animateScroll()
}
二、在components新建Pagination 新建index.vue文件
index.vue内容:
<template>
<div : class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:pager-count="pagerCount"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '../../utils/scroll-to'
export default {
name: 'Pagination',
props: {
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 20
},
pageSizes: {
type: Array,
default() {
return [5,10, 20, 30, 50]
}
},
// 移动端页码按钮的数量端默认值5
pagerCount: {
type: Number,
default: document.body.clientWidth < 992 ? 5 : 7
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
data() {
return {
};
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
handleSizeChange(val) {
if (this.currentPage * val > this.total) {
this.currentPage = 1
}
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
}
}
}
</script>
<style scoped>
.pagination-container {
/* background: #fff; */
/* padding: 32px 16px; */
height: 50px;
margin-top:30px;
/* position: fixed; */
right: 90px;
bottom: 20px;
}
.pagination-container.hidden {
/* display: none; */
}
</style>
三、在main.js引入分组组件 ,并且挂在全局
import Pagination from "./components/Pagination";
Vue.component('Pagination', Pagination)
四、需要用到的页面,使用关在全局的方法名即可使用
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getSocialNumberList"
/>
复制粘贴 即可正常使用样式问题调一下即可,@pagination为获取列表的方法,在改变条数或者页数的时候触达
4.vue分页组件--封装:方法二(了解)
方法二与方法一的区别:方法一是全局引入,方法二是组件部分引入,即在使用的地方引入;
另一个区别在方法二的第5点,在方法一中也是可以用的。
一、分页的原理:
1.1 分页的原理
通过element-ui 的内置组件pagination实现分页,任何分页都有以下五个部分组成:
记录的总条数
每页显示的记录条数
总页数
当前是第几页
当前页的所有记录
1.2 真假分页
pagination实际上是一个组件,组件里设置了分页常用到的参数,让pagination组件得到分页常用的参数值,这就能够实现分页了。
真分页:当你目前在首页的时候,点击“第二页”或“下一页”的时候,会重新向后端发送请求,请求第二页的数据
假分页:一开始从后端发送请求获取所有的数据,前端通过在组件的方式对数据进行分页,再点击分页的按钮的时候,数据其实已经在浏览器缓存的缓存中了,不需要再请求后端接口
二、后端-PageHelper的使用:
1、首先要在pom.xml中添加pageHelper的依赖
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
2、在映射文件中书写“SQL查询”语句;注意:语句结束不要用“;”
<select id="QueryProductsById" resultMap="ProductsMap">
SELECT
<include refid="products_cloumn_list"/>
FROM products WHERE id = #{Id}
</select>
3、书写Controller类,注意:调用PageHelper的startPage方法一定要在调用接口中方法前。
@RequestMapping("/PageInfo")
public PageInfo<Products> pageInfo(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<Products> list = productsDaoService.QueryProducts();
PageInfo<Products> pageInfo = new PageInfo<Products>(list);
return pageInfo;
}
4、启动tomcat服务器,使用Apipost对接口进行测试,如果接口没有问题的话,就会在“实时响应”中获取到返回值信息。
三、前端-Pagination的使用:
(使用pagination之前,需要会element-UI有初步的了解),因为使用pagination就是一个从vue-element-admin上“搬运”代码的过程。具体可以在element集成上搜索“pagination”进行查看
1、添加<template>标签的内容到需要分页的页面中 (前1、2、3步骤与方法一相同)
<pagination
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.limit"
@pagination="getList" />
2、根据element集成中,在<script>中导入Pagination组件
import Pagination from '@/components/Pagination'
pagination组件中index.vue的内容如下:
<template>
<div :class="{'hidden':hidden}" class="pagination-container">
<el-pagination
:background="background"//背景色 true 为有背景色,false为无背景色
:current-page.sync="currentPage" //当前页
:page-size.sync="pageSize" //页面的大小
:layout="layout"
:page-sizes="pageSizes"
:total="total" //总页数
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to'
export default {
name: 'Pagination',
props: {
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 20
},
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
}
}
}
</script>
<style scoped>
.pagination-container {
background: #fff;
padding: 32px 16px;
}
.pagination-container.hidden {
display: none;
}
</style>
同方法一 一样,可以进行适当的修改,或者如果不想要某些功能,删除对应的部分即可
3、注册本地组件,并且因为在添加<template>标签的时候,绑定的有属性和方法,所以要对属性进行声明,以及方法的实现
export default {
components: { Pagination },
data() {
return {
list: [{
//查询出来的商品集合
}],
total: 0,
listQuery: {
page: 1,
limit: 20
}
}
},
methods: {
getList() {
// 获取数据
}
}
}
4、实现 getList() 方法,发送axios请求获取后端传递的数据,分别将返回的总条数和数据信息分贝赋给本地的total、list集合
getList() {
// 获取数据
var vm = this;
this.axios({
method: 'get',
url: 'http://localhost:8080/ssm-template/products/PageInfo?pageNum='+vm.listQuery.page+'&pageSize='+vm.listQuery.limit
})
.then(function (response) {
vm.total = response.data.total;
vm.list = response.data.list;
})
},
5、使用 created()方法,让页面加载时候调用 getList()方法,实现分页即可 :
created() {
this.getList()
},
效果图如下:
5.实现思路:如何实现分页器组件
思路:基于连续页码进行判断
需要添加分页器的组件(Search组件)中
<!-- 分页器 -->
<Pagination
:pageNo="searchParams.pageNo"
:pageSize="searchParams.pageSize"
:total="total"
:continues="5"
@getPageNo="getPageNo"
/>
1)在分页器组件上传递【当前页码pageNo】、【每页展示的数据pageSize】、【总的数据total】、【连续的页码(重要)】,定义一个【自定义事件getPageNo】把用户点击的【当前页码pageNo】传递回来,并进行数据请求
2)methods中定义函数接受分页器传回来的【当前页pageNo】
1)分页器,分成三部分 ------【如下图】
分页器组件(Pagination)中
1)通过props取得 Search组件传递的参数
props: ["pageNo", "pageSize", "total", "continues"],
2)在分页器组件计算属性computed中计算总共多少页/最后一页 - this.total / this.pageSize
【记得向上取整Math.ceil(),例:当总的数据total=30,每页的数据pageSize=3,那么10页刚刚好展示完毕,如果每页的数据pageSize=4,有7页展示4条数据,还有2条需要下一页展示,所以进行取整,Math.ceil(30/4)=8】
3)在分页器组件计算属性computed中计算连续页码【至少5页】的起始数字start、结束数字end【当前页pageNo在连续页码中】
情况判断一:连续的页码 > 总的页数 【start=1,end=总的页数】
情况判断二:连续的页码 < 总的页数 【计算 start = pageNo - parseInt(continues / 2)、end = pageNo + parseInt(continues / 2);】
分情况一:start数字出现0 | 负数 【continues=5,pageNo=1、2的时候】
分情况二:end数字大于总页码 【continues=5,totalPage=30,pageNo=29、30的时候】
记得:最后把 start、end返回
上下一页 、第一页、最后一页的判断
上一页:如果当前页pageNo=1,就不显示上一页按钮,绑定点击事件,点击触发getPageNo自定义事件,把当前页pageNo-1当参数传递回search组件,请求上一页的数据
第一页:如果连续页码的起始数字start>1,就显示前面定义好的第一页;小于的话,显示连续页码中的第一页按钮。点击事件同上,由于可能处理选中状态,所以绑定一个类【已经在css中定义好的】,添加选中颜色,当然需要判断是否是选中的页
省略...小点:当连续页码的start=3时,显示,也就表示,他们之间还有一页
连续页码:通过v-for遍历数字,遍历连续页码中end,并判断其中的元素page>start,才显示【因为传过来的连续页码为5,所以在分页器中连续页码出现最大的就是end-start=5,去掉start之前的页码,才能使连续页码为5】,其他同上
省略...小点 | 最后一页 | 下一页:计算同上【totalPage是上面已经算完的总页数|最后一页】
静态组件
<template>
<div class="pagination">
<button>1</button>
<button>上一页</button>
<button>···</button>
<button>3</button>
<button>4</button>
<button>5</button>
<button>6</button>
<button>7</button>
<button>···</button>
<button>9</button>
<button>上一页</button>
<button style="margin-left: 30px">共 60 条</button>
</div>
</template>
<script>
export default {
name: "Pagination",
}
</script>
<style lang="less" scoped>
.pagination {
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;
}
}
}
</style>
6.el-pagination实现分页功能
如果只放el-pagination组件,只是一个静态的分页展示,还需要绑定数据列表,达到动态分页功能。
静态展示如下
其中最主要的几行代码如图:
对于currentPage、pageSize都要在数据中定义一下,如图
对于handleSizeChange、handleCurrentChange都要实现一下该函数
接下来是最最关键的一步,需要绑定数据加载
对于需要动态加载的组件,进行绑定,比如说绑定到el-table或者el-card中,我的数据储存在carddata中,.slice就是用来分割数据的,根据当前页面的大小以及页面定位进行数据的展示。
前后端分页:
需要注意的是当我们使用后端分页时,要注意前端就不能进行分页了,前端就只负责请求,后台已经把页分好了,不然你的页面就只会显示第一页的数据,其他页都是显示“暂无数据”;前端分页相对来说不会这么麻烦,但还是要多注意。
后端分页:
就是数据在后台已经分好页了,前端只需要用请求去获取数据即可,后端分页的好处是只会把当前页的数据给拿下来,网页加载的速度会很快,但是不足就是每跳转一次,前端都要向后台发送一次请求。
前端分页:
就是用请求从后台把所有的数据拿下来,然后进行分页,如果当数据足够大时,网页就会加载的很慢,唯一的好处就是只需要向后台请求一次就可以了。
参考链接:
https://blog.csdn.net/weixin_69318049/article/details/127072290
版权归原作者 coinisi_li 所有, 如有侵权,请联系我们删除。