数据库分页,分页数据搜索功能

在前面 无刷新分页 中,已经实现了简单的分页功能,这一篇我们将对其进行扩展,为其实现搜索功能。 首先预览下搜索将要实现的效果: 点击搜索列头,弹出搜索区域(包括排序、清除、搜索框),搜索框中输入搜索结果,确定后完成搜索,多列搜索将对搜索条件进行叠加处理。
里提供4种搜索类型(字符、数值、日期、多选值),每种搜索提供相应的输入选项:
字符类型:提供包含、等于、开头、结尾搜索选项。 分页数据搜索功能数据库分页
数值类型:提供 =、>=、<、<=搜索选项。 分页数据搜索功能数据库分页
日期类型:提供开始、结束搜索选项。 分页数据搜索功能数据库分页
多选值:提供值的多选方式。 分页数据搜索功能数据库分页
下面来实现搜索功能,首先是为列头绑定事件,这里需要找出那些可用于搜索的列头,前面已经提到过搜索支持的4种类型,在搜索中需要为这些列头设置相应的属性,这里自定义queryType属性,比如:
名称
先不用关注上面使用的Lable服务器控件,这里暂时先只作为查询支撑控件。 接下来可以找出所有标有queryType属性的标签,这些标签的父控件即为可用于搜索的列头,为其绑定鼠标单击事件:
tableObj.find('[queryType]').each(function(n){ labelObj[n] = $(this); parentObj = labelObj[n].parent(); parentObj.bind('click', function(){ getSearchArea(labelObj[n]); }); }); //获取搜索区域 function getSearchArea(o){ }
getSearchArea方法里面,我们需要先创建搜索区域(一段标准HTML代码),设置其样式可浮动、绝对定位,创建后附加到页面中,并以列头作为参照物获取坐标并显示:
function setPosition(params){ //获取列头坐标 var tdObj = params.label.parent(); var left = tdObj.position().left + 5; var top = tdObj.position().top + 20; if(left + 200 > SCREEN_WIDTH){ left = SCREEN_WIDTH - 200; } //设置搜索区域坐标 searchMap.Item(params.containerId).Item('main').css({ left: left, top: top}); searchMap.Item(params.containerId).Item('main').show(); }
上面方法中的searchMap.Item(params.containerId).Item('main')为创建好的搜索主区域,先不关注它,后面再介绍。 然后获取所有搜索对象:升序、降序、清除、确定、取消,分别为其绑定相应的事件方法。 这样,搜索区域已经被创建好,点击列表头时将显示于表头下方,在本篇中,创建的搜索区域已经包含了所有搜索方式的4种输入框,并且为其定义唯一的编号,后面的操作只是根据搜索类型来显示或隐藏,大家可参照源文件进行对比,这里不进行描述。
接下来要思考的是如何获取搜索结果,从上面信息来看,每一次搜索都涉及到下面几个关键信息: 搜索字段、搜索类型、搜索条件、搜索内容。 因此,我们至少需要将这些关键信息传递给分页控件,最常用的方法的是将每类信息作为一个参数通过URL传参方式传递给分页控件,但这种方式会造成参数数量增多,而且扩展不灵活。 这里用另一种方式实现,我们定义一种数据协议,将获取到的每类信息按照“类型-值”的方式进行组合,最后将每一列的搜索结果作为一个整体,样式如下: columnName┝COLON┥VAL┝SEPARATOR┥ queryType┝COLON┥text┝SEPARATOR┥ condition┝COLON┥contain┝SEPARATOR┥ value┝COLON┥10┝SEPARATOR┥ ┝END┥ 这里以┝END┥作为多列的分隔符,┝SEPARATOR┥作为每种信息的分隔符,┝COLON┥作为各具体信息描述及结果的分隔符。 格式定义好了,可以以此为目标进行搜索实现,每一次搜索的结果都需要进行保存,用于下一次搜索的条件叠加。 这里用一个字典来保存搜索结果:
var searchResult = new Map(); //搜索结果,格式为:字段、搜索信息集合(顺序为:搜索类型、搜索条件、值)
前面提到过获取搜索主区域:searchMap.Item(params.containerId).Item('main')的方法,这是另一个字典对象,保存类搜索信息区域,控制显示及隐藏,定义为:
var searchMap = new Map(); //页面控件对象,格式为:各列唯一编号、对象类型、对象
在每一次搜索完成时,根据获取到的列、类型、搜索结果,组合成前面定义的数据格式,提交给后台进行处理,并保存至searchResult中,下面是一些以文本搜索方式例的关键代码:
//确定按钮点击事件 function okButtonClick(params){ searchByText(params); getSearchResult(params); //提交搜索条件 pagerObj.Page(1); searchMap.Item(params.containerId).Item('main').hide(); } //获取文本搜索内容 function searchByText(params){ if(params.queryType != 'text'){ return; } createSearchResult(params); searchResult.Item(params.columnName)[0] = params.queryType; //搜索类型 searchResult.Item(params.columnName)[1] = searchMap.Item(params.containerId).Item('textCondition').val(); //搜索条件 searchResult.Item(params.columnName)[2] = searchMap.Item(params.containerId).Item('textResult').val(); //搜索结果 } //添加搜索结果,格式为:字段名、搜索类型、搜索条件、结果 function createSearchResult(params){ if(!searchResult.Exists(params.columnName)){ searchResult.Add(params.columnName, new Array()); } } //获取搜索结果值,组合成搜索结果格式 function getSearchResult(params){ var result = ''; var keys = searchResult.Keys(); for(var i = 0; i < keys.length; i++){ result += 'columnName┝COLON┥' + keys[i] + '┝SEPARATOR┥'; result += 'queryType┝COLON┥' + searchResult.Item(keys[i])[0] + '┝SEPARATOR┥' result += 'condition┝COLON┥' + searchResult.Item(keys[i])[1] + '┝SEPARATOR┥' result += 'value┝COLON┥' for(var j = 2; j < searchResult.Item(keys[i]).length; j++){ if(j > 2){ result += '┝JOIN┥'; } result += searchResult.Item(keys[i])[j] ; } result += '┝SEPARATOR┥' result += '┝END┥'; } $('#' + searchResultId).val(result); }
至此,前台搜索处理已经结束。 接下来,在分页控件获取到提交的数据源后,对其进行数据解析,由于前面定义的数据协议在后台可以解析成键值对,我们可以对其键、值进行判断、处理,最终生成查询的WHERE条件,还是以文本搜索方式为例:
/// /// 解析提交数据格式 /// public static Dictionary> AnalyseDataSource(string dataSource) { Dictionary> dictSource = new Dictionary>(); int index = 0; string[] sltRows = Regex.Split(dataSource, "┝END┥"); foreach (string strRow in sltRows) { if (strRow.Length == 0) { continue; } string[] sltCols = Regex.Split(strRow, "┝SEPARATOR┥"); foreach (string strCol in sltCols) { if (strCol.Length == 0) { continue; } string[] sltVals = Regex.Split(strCol, "┝COLON┥"); if (sltVals.Length != 2) { continue; } if (!dictSource.ContainsKey(index)) { dictSource.Add(index, new Dictionary()); } string col = sltVals[0]; if (dictSource[index].ContainsKey(col)) { continue; } string val = sltVals[1]; dictSource[index].Add(col, val); } index++; } return dictSource; } /// /// 解析分页搜索查询条件 /// public string AnalysePagerWhere(string dataSource) { StringBuilder sb = new StringBuilder(); Dictionary> dictSource = AnalyseDataSource(dataSource); IDataAnalyse analyseObj = null; foreach (int keyIndex in dictSource.Keys) { analyseObj = null; switch (dictSource[keyIndex]["queryType"]) { case "text": analyseObj = new DataAnalyseText(dictSource[keyIndex]["columnName"], dictSource[keyIndex]["condition"], dictSource[keyIndex]["value"]); break; case "date": analyseObj = new DataAnalyseDate(dictSource[keyIndex]["columnName"], dictSource[keyIndex]["value"]); break; case "numeric": analyseObj = new DataAnalyseNumeric(dictSource[keyIndex]["columnName"], dictSource[keyIndex]["condition"], dictSource[keyIndex]["value"]); break; case "values": analyseObj = new DataAnalyseValues(dictSource[keyIndex]["columnName"], dictSource[keyIndex]["value"]); break; } if (analyseObj != null) { sb.Append(analyseObj.GetWhere()); } } return sb.ToString(); } /// /// 数据源解析接口 /// public interface IDataAnalyse { string GetWhere(); } /// /// 解析字符查询 /// public class DataAnalyseText : IDataAnalyse { private string columnName = ""; private string condition = ""; private string val = ""; public DataAnalyseText(string columnName, string condition, string val) { this.columnName = columnName; this.condition = condition; this.val = val; } public string GetWhere() { string whereFmt = ""; switch (condition) { case "contain": whereFmt = " AND ({0} LIKE '%{1}%' {2})"; break; case "equal": whereFmt = " AND ({0} = '{1}' {2})"; break; case "start": whereFmt = " AND ({0} LIKE '{1}%' {2})"; break; case "end": whereFmt = " AND ({0} LIKE '%{1}' {2})"; break; } string orWhere = ""; if (val.Length == 0) { orWhere = string.Format(" OR {0} IS NULL", columnName); } return string.Format(whereFmt, columnName, val, orWhere); } }
解析完成后的数据,在分页控件中进行调用,我们增加一个分页控件PagerBase,继承自FMPager,用于实现获取解析完成后的数据,并供其它具体分页控件调用: 
public class PagerBase : FMPager { protected string orderSource = ""; protected override void _disibledevent=>base.OnLoad(e); //获取查询条件 string querySource = HTMLHelper.Form("querySource"); orderSource = HTMLHelper.Form("orderSource"); DataAnalyseUtil util = new DataAnalyseUtil(); WHERE = util.AnalysePagerWhere(querySource); } public override void DataBind() { base.DataBind(); } public string WHERE { get { return where; } set { where = value; } } private string where = ""; public string ORDER_BY { get { return orderBy; } set { orderBy = value; } } private string orderBy = ""; }
改造上一篇中使用的分页控件,将它的父类从FMPager改成PagerBase,将基类获取到的查询条件及排序条件带入: 
/// /// 存储过程分页 /// public class ProcPager : PagerBase { protected override void _disibledevent=>base.OnLoad(e); FM.Business.ProcPager inf = new Business.ProcPager(); this.ORDER_BY = orderSource.Length > 0 ? orderSource : "NAME"; int recordCount = 0; string columns = "ID, NAME, VAL, INT_VAL, MUTIL_VAL, DATE_VAL"; DataSet ds = inf.GetProcList("TEST", columns, WHERE, ORDER_BY, this.CurrentPageIndex, this.PageSize, ref recordCount); this.RecordCount = recordCount; this.DataSource = ds.Tables[0].DefaultView; base.DataBind(); } }
这样,分页控件已经实现了按前台提交过来的搜索条件对数据进行的过滤。 最后来改造控件输出及前台页面显示。 控件输出,在原有的基础上为搜索列头添加搜索属性:
名称 数值 多选值 日期
<%# Eval("NAME") %> <%# Eval("VAL") %> <%# Eval("INT_VAL")%> <%# Eval("MUTIL_VAL")%> <%# Eval("DATE_VAL")%>

前台调用,增加对搜索对象PagerSearch的引用,PagerSearch是我们封装好的对象,上面已经提到了其中的一些关键方法:
var pagerObj = null; var searchObj = null; function LoadInfo(){ var url = 'AjaxHandler/ProcPager.aspx'; searchObj = new PagerSearch({ ajaxHandler: 'WebServices/QueryHandler.asmx/GetTestValues' }); pagerObj = new PagerObj({ containerId: 'divPager', url: url, searchObj: searchObj }); pagerObj.Page(1); }
到此为此,整个搜索功能已经全部实际,运行的搜索页面,点击每列的列头,就可以看到本篇前面的预览效果。
Demo下载
Tags: 

延伸阅读

最新评论

发表评论