select2,利用ajax高效查询大数据列表(可搜索、可分页)
二、导入css和js到网站上
1.使用CDN,节省自己网站的流量
1
2
|
<link href= "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel= "external nofollow" rel= "stylesheet" />
|
2.下载文件到本地,可以做一些个性的定制(比如说修改提示语)
1
2
3
4
5
|
<!-- select2 --> <link rel= "stylesheet" type= "text/css" href= "${ctx}/common/select2/css/select2.css" rel= "external nofollow" />
<script type= "text/javascript" src= "${ctx}/common/select2/js/select2.full.js" ></script>
<!-- 中文国际化还需要进行参数设置 --> <script type= "text/javascript" src= "${ctx}/common/select2/js/i18n/zh-CN.js" ></script>
|
三、真刀真枪的干起来
第一步、定制页面个性化元素
1
2
3
|
<select name= "parentid" class= "js-data-example-ajax" href= "${ctx}/member/loadMembersInfo.do?uid=${mem.uid}" rel= "external nofollow" style= "width:400px" inputMessage= "请输入会员编号(可部分匹配)" >
<option selected= "selected" value= "666" >沉默王二</option>
</select> |
Java端通过name属性可获得select的value值。
设置class为js-data-example-ajax,页面加载时对该组件进行select2的初始化。
href属性为ajax提供后台检索的URL。
style设置组件的宽度。
inputMessage属性定制个性化的提示语,默认的英文版为Please enter 1 or more characters,中文国际化为“请再输入至少1个字符”,都不太能满足个性化需求,所以需要改,后面介绍。
提供一个默认的option,页面没检索之前显示。
第二步、select2组件化,注释写得很详细了哦
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
<script type= "text/javascript" >
$( function () {
$( "select.js-data-example-ajax" ).each(
function () {
var $ this = $( this );
$ this .select2({
language : "zh-CN" , // 指定语言为中文,国际化才起效
inputMessage : $ this .attr( "inputMessage" ), // 添加默认参数
ajax : {
url : $ this .attr( "href" ),
dataType : 'json' ,
delay : 250, // 延迟显示
data : function (params) {
return {
username : params.term, // 搜索框内输入的内容,传递到Java后端的parameter为username
page : params.page, // 第几页,分页哦
rows : 10 // 每页显示多少行
};
},
// 分页
processResults : function (data, params) {
params.page = params.page || 1;
return {
results : data.data, // 后台返回的数据集
pagination : {
more : params.page < data.total // 总页数为10,那么1-9页的时候都可以下拉刷新
}
};
},
cache : false
},
escapeMarkup : function (markup) {
return markup;
}, // let our custom formatter work
minimumInputLength : 1, // 最少输入一个字符才开始检索
templateResult : function (repo) { // 显示的结果集格式,这里需要自己写css样式,可参照demo
// 正在检索
if (repo.loading)
return repo.text;
var markup = repo.username;
markup += repo.realname;
var markup = "<div class='select2-result-repository clearfix'>" + "<div class='select2-result-repository__avatar'><img src='"
+ repo.headimgUrl + "' /></div>" + "<div class='select2-result-repository__meta'>"
+ "<div class='select2-result-repository__title'>" + repo.username + "</div>" ;
if (repo.realname) {
markup += "<div class='select2-result-repository__description'>" + repo.realname + "</div>" ;
}
markup += "<div class='select2-result-repository__statistics'>"
+ "<div class='select2-result-repository__forks'><i class='fa fa-user'></i> 下级会员数" + repo.children_count + " </div>"
+ "</div>" + "</div></div>" ;
return markup;
},
templateSelection : function (repo) {
return repo.realname || repo.text;
} // 列表中选择某一项后显示到文本框的内容
});
});
});
</script> |
第三步、Java端接收参数并返回结果集,不用我强调,这步很重要
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@RequestMapping(value = "loadMembersInfo" )
public void loadMembersInfo(HttpServletRequest request, HttpServletResponse response) throws IOException { Integer uid = StrUtil.parseStringToInt(request.getParameter( "uid" ));
Members mem = this .memberService.selectByPrimaryKey(uid);
// 分页参数的转换,需要和前台select2进行匹配,下文放代码
BaseConditionVO vo = getBaseConditionVOForTable(request);
vo.addParams( "username" , StrUtil.getUTF8String(request.getParameter( "username" )));
vo.addParams( "uid" , uid);
// 封装结果集,和前台select2也是匹配的。
PageGrid page = createPageGrid( this .membersMapper.getPromoterList(vo, vo.createRowBounds()), vo,
this .membersMapper.searchPromoterTotalCount(vo));
// 以json格式写入到response
out(page, response);
} |
接下来,把关键的源码贴出来,可能和你的项目不吻合,但可以参考。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
BaseConditionVO.Java public class BaseConditionVO { public final static int PAGE_SHOW_COUNT = 50;
private int pageNum = 1;
private int numPerPage = 0;
private int totalCount = 0;
private String orderField;
private String orderDirection;
/**
* @Fields ps : 对参数类型进行封装.
*/
private Map<String, Object> mo = new HashMap<String, Object>();
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this .pageNum = pageNum;
}
public int getNumPerPage() {
return numPerPage > 0 ? numPerPage : PAGE_SHOW_COUNT;
}
public void setNumPerPage(int numPerPage) {
this .numPerPage = numPerPage;
}
public String getOrderField() {
return orderField;
}
public void setOrderField(String orderField) {
this .orderField = orderField;
}
public String getOrderDirection() {
return "desc" .equals(orderDirection) ? "desc" : "asc" ;
}
public void setOrderDirection(String orderDirection) {
this .orderDirection = orderDirection;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this .totalCount = totalCount;
}
public int getStartIndex() {
int pageNum = this .getPageNum() > 0 ? this .getPageNum() - 1 : 0;
return pageNum * this .getNumPerPage();
}
public RowBounds createRowBounds() {
RowBounds ro = new RowBounds( this .getStartIndex(), this .getNumPerPage());
return ro;
}
/**
* @Title: addParams
* @Description: 添加查询条件
* @param key
* @param value
*/
public void addParams(String key, Object value) {
this .getMo().put(key, value);
}
/**
* @Title: getParams
* @Description: 获取查询条件
* @param key
* @return
*/
public Object getParams(String key) {
return this .getMo().get(key);
}
/**
* @return the mo
*/
public Map<String, Object> getMo() {
return mo;
}
/**
* @param mo
* the mo to set
*/
public void setMo(Map<String, Object> mo) {
this .mo = mo;
}
} |
selec2的分页和Java端分页参数匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
protected BaseConditionVO getBaseConditionVOForTable(HttpServletRequest req) { BaseConditionVO vo = new BaseConditionVO();
// 当前页
int currentPage = StrUtil.parseStringToInt(req.getParameter( "page" ));
// 一页显示多少行
int sizes = StrUtil.parseStringToInt(req.getParameter( "rows" ));
// 排序
String sortOrder = StrUtil.getString(req.getParameter( "sord" ));
String sortCol = StrUtil.getString(req.getParameter( "sidx" ));
vo.setNumPerPage(sizes);
vo.setPageNum(currentPage);
vo.setOrderField(sortCol);
vo.setOrderDirection(sortOrder);
return vo;
} |
Java端到select2端的数据封装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
@XStreamAlias( "pageGrid" )
@SuppressWarnings( "rawtypes" )
public class PageGrid { private int page;
// 总页数,和select2的processResults.pagination匹配
private int total;
private int records;
// 数据结果集,和select2的processResults.results匹配
private List data;
public int getPage() {
return this .page;
}
public void setPage(int page) {
this .page = page;
}
public int getTotal() {
return this .total;
}
public void setTotal(int total) {
this .total = total;
}
public int getRecords() {
return this .records;
}
public void setRecords(int records) {
this .records = records;
}
public List getData() {
return this .data;
}
public void setData(List data) {
this .data = data;
}
} |
MySQL获取的数据源和PageGrid进行转换匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
protected PageGrid createPageGrid(List list, BaseConditionVO vo, int searchTotalCount) { PageGrid pageGrid = new PageGrid();
// 数据
pageGrid.setData(list);
// 当前页
pageGrid.setPage(vo.getPageNum());
// 总数目
pageGrid.setRecords(list.size());
// 总页数
int total = 0;
if (pageGrid.getRecords() != 0) {
total = searchTotalCount % vo.getNumPerPage() == 0 ? searchTotalCount / vo.getNumPerPage()
: searchTotalCount / vo.getNumPerPage() + 1;
}
pageGrid.setTotal(total);
return pageGrid;
} |
mybatis的分页,超简单,只要设置了createRowBounds,mybatis就会自动为你分页,这个就厉害了。
1
|
List getPromoterList(BaseConditionVO vo, RowBounds createRowBounds); |
sql语句,这里的关键点是必须要回传id(m.uid as id)到select2.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<select id= "getPromoterList" resultType= "hashmap" parameterType= "map" >
select
m.uid as id,
convert(m.username,char) username,
m.realname,
m.children_count,
m.headimgUrl
from
members m
where m.deleteflag=0
< if test= "mo.username != ''" >and m.username like CONCAT( '%' , '${mo.username}' , '%' )</ if >
<choose>
<when test= "orderField !=null and orderField !=''" >
ORDER BY ${orderField}
< if test= "orderDirection != null and orderDirection != ''" >${orderDirection}</ if >
</when>
<otherwise>
order by m.username DESC
</otherwise>
</choose>
</select> |
你是不是没看见mysql的分页limit,嗯,这里无须关注,这就是框架要为我们做的事情。
总数
1
|
int searchPromoterTotalCount(BaseConditionVO vo); |
count(0)就好
1
2
3
4
5
6
7
|
<select id= "searchPromoterTotalCount" resultType= "java.lang.Integer" parameterType= "map" >
select count(0) as a
from
members m
where m.deleteflag=0
< if test= "mo.username != ''" >and m.username like CONCAT( '%' , '${mo.username}' , '%' )</ if >
</select> |
out输出到response中
1
2
3
4
5
6
|
protected void out(Object result, HttpServletResponse response) throws IOException { ServletOutputStream out = response.getOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(out, result);
out.flush();
} |
到这,select2的remote功能在代码部分就完全贴出来完了。
不过,我最后还是要强调几个点:
1.分页的参数Java端和select2一定要对照起来。
2.回传的数据一定要传递一个id回来,否则回来的列表不能选中,为什么呢?调查select2的源码可以知道。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
Results.prototype.option = function (data) {
var option = document.createElement( 'li' );
option.className = 'select2-results__option' ;
var attrs = {
'role' : 'treeitem' ,
'aria-selected' : 'false'
};
if (data.disabled) {
delete attrs[ 'aria-selected' ];
attrs[ 'aria-disabled' ] = 'true' ;
}
// id为空的情况下,删除的aria-selected,而aria-selected恰好又是列表选中的关键属性。 // 这个就是个坑,只能这么说,select2给出的api上完全不讲这点,我去!!!!!!! if (data.id == null ) {
delete attrs[ 'aria-selected' ];
}
......
} |
3.form表单如何获取select2的值?答案是,1.返回结果集必须有id,2.input标签上必须要name属性。
4.如何自定义inputMessage呢?
在select2.js中找到以下代码,注意注释部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
S2.define( 'select2/data/minimumInputLength' ,[
], function () {
function MinimumInputLength (decorated, $e, options) {
this .minimumInputLength = options.get( 'minimumInputLength' );
// inputMessage
this .inputMessage = options.get( 'inputMessage' );
decorated.call( this , $e, options);
}
MinimumInputLength.prototype.query = function (decorated, params, callback) {
params.term = params.term || '' ;
if (params.term.length < this .minimumInputLength) {
this .trigger( 'results:message' , {
message: 'inputTooShort' ,
args: {
minimum: this .minimumInputLength,
input: params.term,
inputMessage : this .inputMessage, // inputMessage,传递给i18n
params: params
}
});
return ;
}
decorated.call( this , params, callback);
};
return MinimumInputLength;
}); |
select2.js中defaults中增加上inputMessage
1
2
3
4
5
6
7
|
this .defaults = {
... minimumInputLength: 0,
inputMessage: '' ,
maximumInputLength: 0,
...
}; |
然后在zh-CN.js文件中修改inputTooShort方法
1
2
3
4
5
6
7
8
|
inputTooShort : function (e) {
if (e.inputMessage) {
return e.inputMessage; // 增加inputMessage
} else {
var t = e.minimum - e.input.length, n = "请再输入至少" + t + "个字符" ;
return n
}
}, |
原文链接:http://blog.****.net/qing_gee/article/details/72519313