分页显示数据对项目开发中尤为重要,同时能提升用户体验,下面的前端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 {@AutowiredUserServiceImpl 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 {@AutowiredUserMapper userMapper;@Overridepublic 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中查询数据库的数据而已,就不多写了,以上就是前后端实现分页的方法,其实方法不止这一种,在控制台打印的数据我们可以看到,后端传到前端的参数还有是否为第一页(最后一页)、是否存在上一页(下一页),我们还可以通过这些参数来判断并对分页的导航栏进行动态控制。