分页显示数据对项目开发中尤为重要,同时能提升用户体验,下面的前端css、js是我引用这篇文章的《使用Vue开发一个分页插件》,我在这个的基础上结合了后端稍微完善了一下,修改了disable的样式,在里面加了pointer-events: none;来防止在首尾页处点击事件仍然生效。
1、前端
前端使用了vue全局组件的方式做了一个分页的导航栏,总体有四个部分(css样式、js文件写的Vue全局组件、html及html中的vue代码)
样式:page-nav.css
div.page-nav{
font-size: 12px;
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
color: #666;
user-select: none;
}
div.page-nav ul{
padding: 0;
margin:0;
}
div.page-nav ul li{
display: inline-block;
min-width:30px;
min-height:30px;
border-radius:3px;
line-height: 30px;
text-align: center;
margin: 0 6px;
cursor: pointer;
}
div.page-nav ul li.active{
background: #1796e0;
color:#fff;
}
div.page-nav ul li.disable{
color: #ccc;
pointer-events: none;
}
page-nav.js
Vue.component('page-nav',{
props:{
total:{
type:[Number,String],
default:0
},
pagesize:{
type:[Number,String],
default:1
},
page:{
type:[Number,String],
default:1
}
},
template:'<div class="page-nav">'+
'<ul>'+
'<li :class="page==1?\'disable\':\'\'" @click="prev">上一页</li>'+
'<li :class="page==1?\'disable\':\'\'" @click="toFirst">首页</li>'+
'<li v-for="item in list" :class="[item==page?\'active\':\'\']" @click="handleClick">'+
'{{item}}'+
'</li>'+
'<li :class="page==totalCount?\'disable\':\'\'" @click="toEnd">尾页</li>'+
'<li :class="page==totalCount?\'disable\':\'\'" @click="next">下一页</li>'+
'<li>总共{{totalCount}}页</li>'+
'</ul>'+
'</div>',
data(){
return {
totalCount:0 //总页数
}
},
computed:{
list(){
let list=[];
//计算总页数
this.totalCount=this.total/this.pagesize;
//超限控制
if(this.page<=0){
this.page=1;
}
if(this.page>=this.totalCount){
this.page=this.totalCount;
}
//计算显示页码
if(this.totalCount>5){
if(this.page>2&&this.page<this.totalCount-2){
list=[this.page-2,this.page-1,this.page,this.page+1,this.page+2];
}else if(this.page<=2&&this.page>0){
for(let i=1;i<=5;i++){
list.push(i);
}
}else if(this.page>=this.totalCount-2&&this.page<=this.totalCount){
for(let i=4;i>=0;i--){
list.push(this.totalCount-i);
}
}
}else{
for(let i = 1;i<=this.totalCount;i++){
list.push(i);
}
}
return list;
}
},
methods:{
//页码点击事件
handleClick(e){
let page=parseInt(e.target.innerText);
let {count,total }=this;
this.$emit('pagechange',{page,count,total});
},
//前一页
prev(e){
if(!e.target.classList.contains['disable']){
this.page>1&&this.page--;
let {page,count,total }=this;
this.$emit('pagechange',{page,count,total});
}
},
//下一页
next(e){
if(!e.target.classList.contains['disable']){
this.page<this.totalCount&&this.page++;
let {page,pagesize,total }=this;
this.$emit('pagechange',{page,pagesize,total});
}
},
//首页
toFirst(){
let {page,pagesize,total }=this;
this.$emit('pagechange',{page:1, pagesize, total});
},
//尾页
toEnd(){
let {page,pagesize,total }=this;
this.$emit('pagechange',{page:this.totalCount, pagesize, total});
}
}
});
html:
<div v-if="users != null">
<page-nav :page="startPage" :pagesize="pageSize" :total="total" @pageChange="pageChange"></page-nav>
</div>
html中部分vue代码:
new Vue({
el: '#app',
data() {
return {
url: 'http://localhost:8080/',
users: null,
user: {
id: null,
name: '',
age: null,
sex: ''
},
startPage: 1,
pageSize: 5,
total: 30,
isSearch: false
}
},
methods: {
queryUser: function () {
var _this = this;
axios.get(_this.url + 'queryUser', {
params: {
// 这里我把无条件查找和条件查找放一起了,所以这里传一个对象到后端,这句无关紧要
user: JSON.stringify(_this.user),
// 传起始页跟页面大小到后端
startPage: _this.startPage,
pageSize: _this.pageSize
}
})
.then(function (response) {
// 获取回传的user列表
_this.users = response.data.users.list;
// 我在后台传了一个msg
_this.msg = response.data.msg;
// 总记录数(用了pageHelper后在返回的response中包含了记录数信息:total)
_this.total = response.data.users.total;
console.log(response);
})
.catch(function (err) {
console.log(err);
})
},
pageChange(e) { // 点击上一页下一页时改变分页导航的样式,同时查询下一条记录
this.page = e.page;
this.startPage = this.page;
this.queryUser();
}
},
created() {
this.queryUser();
}
});
效果:
注:在不知道参数怎么获取时可以打开控制台,在控制台的打印信息即可看到,如下
2、后端
上面前端的代码就写完了,接下来是后端的代码,这里我是用了SpringBoot来写的。
首先是Controller(控制层),参数是前端传过来的对象Json字符串、起始页及页面大小,返回值是Map(我在实现层ServiceImpl中用了Map来存储要返回前端的数据信息)
import com.exam.yezhihu.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @Author: yzh
* @Description:
* @Date: 2020/9/6 13:17
* @Version: 1.0
*/
@RestController
public class UserController {
@Autowired
UserServiceImpl userService;
@RequestMapping("queryUser")
public Map queryUser(@RequestParam("user") String userJson, @RequestParam("startPage") Integer startPage, @RequestParam("pageSize") Integer pageSize) {
return userService.queryUser(userJson, startPage, pageSize);
}
}
下面是ServiceImpl(业务实现层)
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.exam.yezhihu.bean.UserBean;
import com.exam.yezhihu.mapper.UserMapper;
import com.exam.yezhihu.service.UserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: yzh
* @Description:
* @Date: 2020/9/6 12:49
* @Version: 1.0
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public Map queryUser(String userJson, Integer startPage, Integer pageSize) {
Map info = new HashMap(2);
// 将Json字符串通过fastjson转为JSONObject对象
JSONObject jsonObject = JSONObject.parseObject(userJson);
// 将JSONObject对象转为StockMesBean实体对象
UserBean user = JSON.toJavaObject(jsonObject, UserBean.class);
// 设置起始页跟页面大小
PageHelper.startPage(startPage, pageSize);
// 查询的方法一定要紧跟PageHelper.startPage,否则可能会出现一些错误
List<UserBean> users = userMapper.queryUser(user);
// 将查到的信息转成PageInfo类型
PageInfo<UserBean> userList = new PageInfo<>(users);
if (users.size() == 0) {
info.put("msg", false);
info.put("users", null);
} else {
info.put("msg", true);
// 返回的是PageInfo类型的user信息列表,这里就包含了刚刚在浏览器控制台看到的lastPage等信息
info.put("users", userList);
}
return info;
}
}
至于Mapper层就是数据访问了,这里就是定义一个接口,在Mapper.xml中查询数据库的数据而已,就不多写了,以上就是前后端实现分页的方法,其实方法不止这一种,在控制台打印的数据我们可以看到,后端传到前端的参数还有是否为第一页(最后一页)、是否存在上一页(下一页),我们还可以通过这些参数来判断并对分页的导航栏进行动态控制。