手写前端分页组件
服务端接口开发
-
个人理解
Mybatis-PageHelper的原理是通过AOP在截获我们执行的SQL的时候,再执行一次SQL语句,填充到返回值里
-
使用方法
在pom.xml中添加相关依赖
<!-- mybatis pager --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>com.github.miemiedev</groupId> <artifactId>mybatis-paginator</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>0.9.4</version> </dependency>
在applicationContext-datasource.xml文件中添加相关配置,设置方言为mysql
<!-- 分页插件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageHelper">
<property name="properties">
<value>
dialect=mysql
</value>
</property>
</bean>
</array>
</property>
在ProductController.java的list接口添加如下配置,对于不是必传的搜索字段,要置成false,因为在RqquestParam.class注解中规定了default true,即使自己在搜索的时候,不传关键字,require也一定要置为false。动态分页需要用到两个参数pageNum
和pageSize
@RequestMapping("list.do")
@ResponseBody
public ServerResponse<PageInfo> list(@RequestParam(value = "keyword",required = false)String keyword,
@RequestParam(value = "categoryId",required = false)Integer categoryId,
@RequestParam(value = "pageNum",defaultValue = "1") int pageNum,
@RequestParam(value = "pageSize",defaultValue = "10")int pageSize,
@RequestParam(value = "orderBy",defaultValue = "")String orderBy){
return iProductService.getProductByKeywordCategory(keyword, categoryId, pageNum, pageSize, orderBy);
}
在ProductServiceImpl.java接口实现中,添加如下配置
public ServerResponse<PageInfo> getProductByKeywordCategory(String keyword,Integer categoryId,int pageNum,int pageSize,String orderBy){
if(StringUtils.isBlank(keyword) && categoryId == null){
return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.ILLEGAL_ARGUMENT.getDesc());
}
List<Integer> categoryIdList = new ArrayList<Integer>();
if(categoryId != null){
Category category = categoryMapper.selectByPrimaryKey(categoryId);
if(category == null && StringUtils.isBlank(keyword)){
// 没有该分类,并且还没有关键字,这个时候返回一个空的结果集,不报错
PageHelper.startPage(pageNum, pageSize);
List<ProductListVo> productListVoList = Lists.newArrayList();
PageInfo pageInfo = new PageInfo(productListVoList);
return ServerResponse.createBySuccess(pageInfo);
}
categoryIdList = iCategoryService.selectCategoryAndChildrenById(category.getId()).getData();
}
if(StringUtils.isNotBlank(keyword)){
keyword = new StringBuilder().append("%").append(keyword).append("%").toString();
}
PageHelper.startPage(pageNum, pageSize);
// 排序处理
if(StringUtils.isNotBlank(orderBy)){
if(Const.ProductListOrderBy.PRICE_ASC_DESC.contains(orderBy)){
//PageHelper.orderBy方法的参数是(peice desc)中间含有空格,需要分割再拼接
String[] orderByArray = orderBy.split("_");
PageHelper.orderBy(orderByArray[0]+" "+orderByArray[1]);
}
}
List<Product> productList = productMapper.selectByNameAndCategoryIds(StringUtils.isBlank(keyword)?null:keyword,categoryIdList.size()==0?null:categoryIdList);
List<ProductListVo> productListVoList = Lists.newArrayList();
for(Product product : productList){
ProductListVo productListVo = assembleProductListVo(product);
productListVoList.add(productListVo);
}
PageInfo pageInfo = new PageInfo(productList);
pageInfo.setList(productListVoList);
return ServerResponse.createBySuccess(pageInfo);
}
前端分页组件开发
html预留分页容器
<!--分页容器-->
<div class="pagination">
</div>
在list/index.js列表中,加载分页
'use strict';
require('./index.css');
require('page/common/nav/index.js');
require('page/common/header/index.js');
var _mm = require('util/mm.js');
var _product = require('service/product-service.js');
var Pagination = require('util/pagination/index.js');
var templateIndex = require('./index.string');
var page = {
data : {
listParam : {
keyword : _mm.getUrlParam('keyword') || '',
categoryId : _mm.getUrlParam('categoryId') || '',
orderBy : _mm.getUrlParam('orderBy') || 'default',
pageNum : _mm.getUrlParam('pageNum') || 1,
pageSize : _mm.getUrlParam('pageSize') || 10
}
},
init : function(){
this.onLoad();
this.bindEvent()
},
onLoad :function(){
this.loadList();
},
bindEvent : function(){
var _this = this;
// 排序的点击事件
$('.sort-item').click(function(){
var $this = $(this);
// 页码置为1
_this.data.listParam.pageNum= 1;
// 如果点击的是默认排序
if($this.data('type') === 'default'){
// 已经是active样式
if($this.hasClass('active')){
return;
}
// 其他
else{
$this.addClass('active').siblings('.sort-item')
.removeClass('active asc desc');
_this.data.listParam.orderBy = 'default';
}
}
//点击价格排序
else if($this.data('type') === 'price'){
// active类的处理
$this.addClass('active').siblings('.sort-item')
.removeClass('active asc desc');
// 升序的处理
if(!$this.hasClass('asc')){
$this.addClass('asc').removeClass('desc');
_this.data.listParam.orderBy = 'price_asc';
}
// 降序的处理
else{
$this.addClass('desc').removeClass('asc');
_this.data.listParam.orderBy = 'price_desc';
}
}
// 重新加载列表
_this.loadList();
});
},
// 加载list数据
loadList : function(){
var _this = this,
listHtml = '',
listParam = this.data.listParam,
$pListCon = $('.p-list-con');
//每次加载之前,显示loading
$pListCon.html('<div class="loading"></div>');
// 删除参数中不必要的字段
listParam.categoryId
? (delete listParam.keyword) : (delete listParam.categoryId);
// 请求接口
_product.getProductList(listParam, function(res){
listHtml = _mm.renderHtml(templateIndex, {
list : res.list
});
$pListCon.html(listHtml);
_this.loadPagination({
hasPreviousPage : res.hasPreviousPage,
prePage : res.prePage,
hasNextPage : res.hasNextPage,
nextPage : res.nextPage,
pageNum : res.pageNum,
pages : res.pages,
});
}, function(errMsg){
_mm.errorTips(errMsg);
});
},
//加载分页信息
loadPagination : function(pageInfo){
var _this = this;
this.pagination ? '' : (this.pagination = new Pagination());
this.pagination.render($.extend({}, pageInfo, {
container : $('.pagination'),
onSelectPage : function(pageNum){
_this.data.listParam.pageNum = pageNum;
_this.loadList();
}
}));
}
};
$(function(){
page.init();
})
封装分页组件
pagination
├─index.css
├─index.js
├─index.string
- index.js
'use strict';
require('./index.css');
var _mm = require('util/mm.js');
var templatePagination = require('./index.string');
var Pagination = function(){
var _this = this;
this.defaultOption = {
container : null,
pageNum : 1,
pageRange : 3,
onSelectPage :null
};
// 事件的处理
$(document).on('click', '.pg-item', function(){
var $this = $(this);
// 对于active和disabled按钮点击,不做处理
if($this.hasClass('active') || $this.hasClass('disabled')){
return;
}
typeof _this.option.onSelectPage === 'function'
? _this.option.onSelectPage($this.data('value')) : null;
});
};
// 渲染分页组件
Pagination.prototype.render = function(userOption){
// 合并选项
this.option = $.extend({},this.defaultOption,userOption);
// 判断容器是否为合法的jQuery对象
if(!(this.option.container instanceof jQuery)){
return;
}
// 判断分页是否只有一页
if(this.option.pages <= 1){
return;
}
// 渲染分页内容
this.option.container.html(this.getPaginationHtml());
};
// 获取分页的html, |上一页| 1 2 3 4 =5= 6 |下一页| 5/6
Pagination.prototype.getPaginationHtml = function(){
var html = '',
option = this.option,
pageArray = [],
start = option.pageNum - option.pageRange > 0
? option.pageNum - option.pageRange : 1,
end = option.pageNum + option.pageRange < option.pages
? option.pageNum + option.pageRange : option.pages;
// 上一页按钮的数据
pageArray.push({
name : '上一页',
value : this.option.prePage,
disabled : !this.option.hasPreviousPage
});
// 数字按钮的处理
for(var i = start; i<= end; i++){
pageArray.push({
name : i,
value : i,
active : (i === option.pageNum)
})
};
// 下一页按钮的数据
pageArray.push({
name : '下一页',
value : this.option.nextPage,
disabled : !this.option.hasNextPage
});
html = _mm.renderHtml(templatePagination, {
pageArray : pageArray,
pageNum : option.pageNum,
pages : option.pages
});
return html;
};
module.exports = Pagination;
-
index.css
.pg-content{ text-align: center; color: #333; } .pg-content .pg-item{ display: inline-block; height: 36px; line-height: 36px; padding: 0 15px; margin: 0 2px; border: 1px solid #ccc; background: #eee; cursor: pointer; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; } .pg-content .pg-item.disabled{ color: #ccc; background: none; cursor: auto; } .pg-content .pg-item.active{ border: 1px solid #f6f6f6; background: none; cursor: auto; } .pg-content.pg-total{ margin-left: 10px; background: none; cursor: auto; }
-
index.string
<div class="pg-content"> {{#pageArray}} {{#disabled}} <span class="pg-item disabled" data-value="{{value}}">{{name}}</span> {{/disabled}} {{^disabled}} {{#active}} <span class="pg-item active" data-value="{{value}}">{{name}}</span> {{/active}} {{^active}} <span class="pg-item" data-value="{{value}}">{{name}}</span> {{/active}} {{/disabled}} {{/pageArray}} <span class="pg-total">{{pageNum}} / {{pages}}</span> </div>