jQuery插件select2利用ajax高效查询大数据列表(可搜索、可分页)
select2是一款jquery插件,是普通form表单select组件的升级版。
可以定制搜索、远程数据集(remote data,本篇主要介绍点)、无限滚动(数据分页功能,这一点很妙)、还有很多高端的参数设置(有需要的下次介绍)。
内置了40种国际化语言,不过这里我们只需要用到中文。
同时支持现代和传统浏览器内置,甚至包括惹人不高兴的ie8。
那么,现在让我们开始一段select2的奇幻之旅吧!
一、惊艳的效果,来一睹为快吧
本地实战结果
二、导入css和js到网站上
1.使用cdn,节省自己网站的流量
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="external nofollow" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
2.下载文件到本地,可以做一些个性的定制(比如说修改提示语)
<!-- 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>
三、真刀真枪的干起来
第一步、定制页面个性化元素
<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组件化,注释写得很详细了哦
<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端接收参数并返回结果集,不用我强调,这步很重要
@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); }
接下来,把关键的源码贴出来,可能和你的项目不吻合,但可以参考。
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端分页参数匹配
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端的数据封装
@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进行转换匹配
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就会自动为你分页,这个就厉害了。
list getpromoterlist(baseconditionvo vo, rowbounds createrowbounds);
sql语句,这里的关键点是必须要回传id(m.uid as id)到select2.
<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,嗯,这里无须关注,这就是框架要为我们做的事情。
总数
int searchpromotertotalcount(baseconditionvo vo);
count(0)就好
<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中
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的源码可以知道。
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中找到以下代码,注意注释部分
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
this.defaults = { ... minimuminputlength: 0, inputmessage: '', maximuminputlength: 0, ... };
然后在zh-cn.js文件中修改inputtooshort方法
inputtooshort : function(e) { if (e.inputmessage) { return e.inputmessage;// 增加inputmessage } else { var t = e.minimum - e.input.length, n = "请再输入至少" + t + "个字符"; return n } },
以上所述是小编给大家介绍的jquery插件select2利用ajax高效查询大数据列表(可搜索、可分页),希望对大家有所帮助