视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
jQuery插件select2利用ajax高效查询大数据列表
2020-11-27 20:06:42 责编:小采
文档
 select2是一款jQuery插件,是普通form表单select组件的升级版。本文主要和大家介绍jQuery插件select2利用ajax高效查询大数据列表(可搜索、可分页),需要的的朋友参考下吧,希望能帮助到大家。

可以定制搜索、远程数据集(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.下载文件到本地,可以做一些个性的定制(比如说修改提示语)

git下载地址

<!-- 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 = "<p class='select2-result-repository clearfix'>" + "<p class='select2-result-repository__avatar'><img src='"
 + repo.headimgUrl + "' /></p>" + "<p class='select2-result-repository__meta'>"
 + "<p class='select2-result-repository__title'>" + repo.username + "</p>";
 if (repo.realname) {
 markup += "<p class='select2-result-repository__description'>" + repo.realname + "</p>";
 }
 markup += "<p class='select2-result-repository__statistics'>"
 + "<p class='select2-result-repository__forks'><i class='fa fa-user'></i> 下级会员数" + repo.children_count + " </p>"
 + "</p>" + "</p></p>";
 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
 }
},

下载本文
显示全文
专题