JQuery中使用select2插件功能之自动完成下拉框动态加载匹配(本地数据与远程数据结合)

前言
最近项目中遇到一个问题:前端加载页面的时候某些页面加载速度很慢,耗时很久;有些页面加载的飞快;因为上面所说的页面都是由同一个程式动态生成的,利用多线程同步机制完成不同的前端页面;因此当时就断定不是程式的大问题;应该是处理数据部分存在问题;在chrome浏览器一测;还真的是大数据的问题;进入页面就加载大批量数据进来;不仅增加数据库的负担 ,前后端处理数据也会造成一定的压力;因为有些函数把这些大数据遍历掉了;耗时非常大。最终找到多个造成此问题的原因;现在就拿其中的一个出来说说;刚好涉及到最新版本的select2插件的一些功能;就如何在select2下拉框大数据的情况下处理以达到流畅、无压力的状态。
一、设计思路
进入前端页面,对于select2下拉框的数据来源;先加载一很小部分数据作为本地数据,先做个简单的分页功能;进来页面之后,点击下拉框加载显示就是本地数据;当在下拉框输入值搜索的时候在本地数据中搜索不到就去远程加载数据;这里说一下,select2原本是有搜索匹配和远程数据这两个功能的,官方文档也有说明;不过因为这两个功能是相对独立的;所以在搜索匹配的时候我对select2的matcher匹配功能方法做了重构;远程功能的方法也是自己写的方法;做法是这样的:当输入值搜索的时候,先匹配本地数据,如果匹配本地数据最后一个都没有合适的就远程访问数据库抓匹配数据,去后台抓的话也是加载一部分数据,做分页功能;返回的数据又作为本地数据叠加;退出页面将重新开始,重新加载。解决这些问题所遇到的坑这里就不一一说了,我已经填好坑了;直接走过去就行了。
二、实现效果(最左匹配实现)
在这里插入图片描述
三、代码实例
1.前端部分
1.1 HTML代码

部分html页面代码,设定div区域,id=“tab2ModalBody”

<div class="box box-primary">
	<form class="form-horizontal" role="form" id="foo">
		<div class="box-body" style="padding-top: 0px;padding-bottom: 0px;">
			<div class="box-body" id="tab2ModalBody" style="padding-bottom: 0px;">
			</div>
		</div>
	</form>
</div>

1.2 JS代码
(1)动态加载html页面内容的function;动态拼接html,及绑定select2事件

       function SetModalField(data,data5) {//data为初始化页面时加载进来的数据
                    var res=[];
                    var selectData = "<option value=\"\"> </option>";// 初始化<option>标签
                        defData = data[i].DATA_DEFAULT.split(";");// 分解初始化数据
                        for (var b = 0; b < defData.length; b++) {//遍历显示的数据
                            selectData += "<option value=\"" + defData[b] + "\">" + defData[b] + "</option>";
                        }
                     fieldTypeString = "<select id=\"" + data[i].TABLE_FIELD + "\"  +
                        "class=\"form-control select tableData sel2\"  
                        " >" + selectData + "</select> ";//将option值拼接在select标签
                        //将上面拼接的html代码嵌入到id=tab2ModalBody的锚下面
                        $("#tab2ModalBody").html(fieldString);
                        //定位sel2结尾的class,就是form-control select tableData sel2的class在jquery中使用select2
                        $(".sel2").select2({
			        theme: 'bootstrap',//主题
			        allowClear: true,//允许清除
			        matcher:matchStart,//自定义匹配功能,调用matcher函数
			    }).on("select2:open", function () {//监听下拉框被打开事件
			    	select2count=0;//先初始化一些参数,匹配时需要用到
			    	select2times=0;
			    	currentSelect2Id=this.id;
			        selectChange(this.id);//事件函数
			    });
   }

(2)当在搜索框输入值做匹配时,会调用对应的下面matcheStart(param,data)函数进行将输入框的值跟本地数据一个个去做匹配;算法可以自定义,下面的匹配功能是最左匹配功能,即从最左开始匹配,有符合的就返回给下拉框显示,注意:params为输入的参数,params.term为输入框的值;data一次次遍历下拉框显示的值,一次只传一个,下拉框有多少值就遍历传多少次。

    function matchStart(params, data) {//遍历一次次匹配
      // If there are no search terms, return all of the data
      if ($.trim(params.term) === '') {
        return data; 
      }
      // Skip if there is no 'text' property
      if (typeof data.text === 'undefined') {
        return null;
      }
      // `data.children` contains the actual options that we are matching against
      select2times++;//标志位从0开始 +1,若匹配本地数据的次数是最后一次的话就去后台请求
      var currentSelect2Qty=($("#"+currentSelect2Id+"").children('option').length);//获取当前下拉框数据总数量n笔
      if(select2times>=currentSelect2Qty){//最后一次进来匹配本地数据
	//先做最后一次匹配
	 if (data.text.toUpperCase().indexOf(params.term.toUpperCase()) == 0) {
			   select2count++;
			  var modifiedData = $.extend({}, data, true);
			  select2times=0;
			  select2count=0;
			  return modifiedData;
		   }else{//如果最后都匹配不到数据,则去后台请求数据
			   if(select2count==0){//标记位,匹配到数据的话,select2count不等于0
			     var option1=remoteSelct2Data(params.term);//调用远程请求function;返回请求的数据
			     if(option1.length>0){//有值则取,清空标志位,返回
				  var newModifiedData= $.extend({},data,option1[0]); //$.extend()合并函数
				  select2times=0;
				  select2count=0;
				  return newModifiedData;
			     }else{//清空标志位,返回null
				  select2times=0;
				  select2count=0;
				  return null;//返回 
			     }

			   }else{//清空标志位,返回null
				  select2times=0;
				  select2count=0;
				  return null;  
			   }

		   }
 	      }else{//不是最后一次进来匹配,  
	  if (data.text.toUpperCase().indexOf(params.term.toUpperCase()) == 0) {
		   select2count++;
		  var modifiedData = $.extend({}, data, true);
		   return modifiedData;
		   }else{
			   return null;
		   }
  }
}

(3)ajax远程请求后台数据,参数为搜索框的值;传递的参数可以自定义。

function remoteSelct2Data(term){	   
	   var jsonparam={
				'term':term,
				'page':pagesize  //pagesize为全局变量,参数可以自己自行增加定义
		   }; 	   
		   $.ajax({
               type: "POST",
               url: '/PostServlet',
               data: JSON.stringify({
                   funCode: funCode,//全局参数,自行定义
                   funData: JSON.stringify({
                       func: 'getSelect2Data',
                       paramData: jsonparam,
                       schema:schema
                   })
               }),
               dataType: "json",//返回的数据是json格式
               async: false,
               success: function (data) {  //远程请求返回的数据data,
                if(data[0].EX == 'NG'){
             	   data=data.splice(1,data.length);
                	   for(var i=0;i<data.length;i++){
                	           //遍历返回的数据,添加到id=currentSelect2Id的select标签元素下面的option值
 	        			$("#"+currentSelect2Id+"").append("<option value='"+data[i].id+"'>"+data[i].text+"</option>");
 	        			options.push({ id : data[i].id,text : data[i].text});
    	        		}
                }
               
               }
           }); 
		   return options;//返回值
       } 
 }	

2.后端部分
2.1后台接受到请求后分发执行的方法doFunction;上一层这里就忽略了;

public String doFunction(FunctionPojo funRequest,//FunctionPojo 自定义的bean,里面包含需要的参数
		HttpServletResponse response) throws Exception {
	JSONObject jsonData = JSONObject.fromObject(funRequest.getFunData());
	String action = jsonData.getString("func");
	String schema=jsonData.getString("schema");
	switch (action) {
	case "getSelect2Data":
		res=getselect2data(schema, jsonData);//执行具体方法
		break;
	}
	return res;
}

2.2 具体的访问数据库执行的方法

 public synchronized  String getselect2data(String schema,JSONObject jsondata){
		ResultSet rs1;
		JSONObject jsonParam=jsondata.getJSONObject("paramData");
		JSONObject json =new JSONObject();
		JSONArray jsonArr=new JSONArray();
		JSONObject jsonOra=new JSONObject();
		jsonOra.put("EX", "NG");
		String select2Sql=queryData.getRegSql(jsonParam);
				try {
					rs1=super.getResultSet(select2Sql, schema, new Object[]{});
					while(rs1.next()){
						if (rs1.getString(1) != null) {
							//System.out.println(rs1.getString(1));
							json.put("id",rs1.getString(1));
							json.put("text", rs1.getString(1));
						}
						jsonArr.add(json);	
					}
					jsonArr.add(0, jsonOra);
				} catch (SQLException e) {
					// TODO 自动生成 catch 块
					jsonOra.put("EX", "异常信息:"+e.getLocalizedMessage());
					jsonArr.add(0, jsonOra);
					e.printStackTrace();
				}
						
		return jsonArr.toString();
	}

2.3 这里嵌套分页功能的sql,半个分页,没有做分页参数;应为原来就已经有了查询数据的sql;所以做优化就要在原来的sql上面再嵌套一层sql,好做分页;至于具体的sql分页效率,可以参考最有效的sql分页

public static synchronized String getRegSql(JSONObject jsonObj){
	String conditionId=jsonObj.getString("currentSelect2Id");
	String select2Sql=jsonObj.getString("currentSelect2DBSql");
	String selectTerm=jsonObj.getString("term");
	String empNo=jsonObj.getString("empNo");
	String prodAreaId=jsonObj.getString("prodAreaId");
	if(select2Sql!=" "&&!select2Sql.equals(" ")){
		select2Sql ="SELECT SEL2.* FROM ( " +select2Sql +"  )SEL2  WHERE ROWNUM<=10  AND   
		      SEL2."+conditionId+" LIKE '"+selectTerm+"%'";       
		}
	return select2Sql;
} 

猜你喜欢

转载自blog.csdn.net/use_admin/article/details/83928215
今日推荐