select2,利用ajax高效查询大数据列表(可搜索、可分页)

栏目: jQuery · 发布时间: 8年前

内容简介:select2,利用ajax高效查询大数据列表(可搜索、可分页)

select2是一款jquery插件,是普通form表单select组件的升级版。

可以定制搜索、远程数据集(Remote data,本篇主要介绍点)、无限滚动(数据分页功能,这一点很妙)、还有很多高端的参数设置(有需要的下次介绍)。

内置了40种国际化语言,不过这里我们只需要用到中文。

同时支持现代和传统浏览器内置,甚至包括惹人不高兴的IE8。

那么,现在让我们开始一段select2的奇幻之旅吧!

一、惊艳的效果,来一睹为快吧

select2,利用ajax高效查询大数据列表(可搜索、可分页) select2,利用ajax高效查询大数据列表(可搜索、可分页) select2,利用ajax高效查询大数据列表(可搜索、可分页)

本地实战结果

select2,利用ajax高效查询大数据列表(可搜索、可分页)

二、导入css和js到网站上

1.使用CDN,节省自己网站的流量

<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" 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" />
<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}" style="width:400px" inputMessage="请输入会员编号(可部分匹配)">
    <option selected="selected" value="666">沉默王二</option>
</select>
  1. Java端通过name属性可获得select的value值。
  2. 设置class为js-data-example-ajax,页面加载时对该组件进行select2的初始化。
  3. href属性为ajax提供后台检索的URL。
  4. style设置组件的宽度。
  5. inputMessage属性定制个性化的提示语,默认的英文版为Please enter 1 or more characters,中文国际化为“请再输入至少1个字符”,都不太能满足个性化需求,所以需要改,后面介绍。
  6. 提供一个默认的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
    }

},

到这里嘛,真的该结束了。

欢迎关注我的公众号,给灵魂片刻安静!

微信扫一扫下方二维码即可关注沉默王二公众号:

select2,利用ajax高效查询大数据列表(可搜索、可分页)

以上所述就是小编给大家介绍的《select2,利用ajax高效查询大数据列表(可搜索、可分页)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Host Your Web Site In The Cloud

Host Your Web Site In The Cloud

Jeff Barr / SitePoint / 2010-9-28 / USD 39.95

Host Your Web Site On The Cloud is the OFFICIAL step-by-step guide to this revolutionary approach to hosting and managing your websites and applications, authored by Amazon's very own Jeffrey Barr. "H......一起来看看 《Host Your Web Site In The Cloud》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具