• 分页数据搜索功能


    在前面 无刷新分页 中,已经实现了简单的分页功能,这一篇我们将对其进行扩展,为其实现搜索功能。
    首先预览下搜索将要实现的效果:
    点击搜索列头,弹出搜索区域(包括排序、清除、搜索框),搜索框中输入搜索结果,确定后完成搜索,多列搜索将对搜索条件进行叠加处理。

    里提供4种搜索类型(字符、数值、日期、多选值),每种搜索提供相应的输入选项:
    字符类型:提供包含、等于、开头、结尾搜索选项。
    数值类型:提供 =、>=、<、<=搜索选项。
    日期类型:提供开始、结束搜索选项。
    多选值:提供值的多选方式。

    下面来实现搜索功能,首先是为列头绑定事件,这里需要找出那些可用于搜索的列头,前面已经提到过搜索支持的4种类型,在搜索中需要为这些列头设置相应的属性,这里自定义queryType属性,比如:

    <td>
    <asp:Label runat="server" columnName="NAME" queryType="text">名称</asp:Label>
    </td>

    先不用关注上面使用的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条件,还是以文本搜索方式为例:

    /// <summary>
    /// 解析提交数据格式
    /// </summary>
    public static Dictionary<int, Dictionary<string, string>> AnalyseDataSource(string dataSource)
    {
    Dictionary
    <int, Dictionary<string, string>> dictSource = new Dictionary<int, Dictionary<string, string>>();
    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, string>());
    }

    string col = sltVals[0];
    if (dictSource[index].ContainsKey(col))
    {
    continue;
    }

    string val = sltVals[1];
    dictSource[index].Add(col, val);
    }

    index
    ++;
    }

    return dictSource;
    }

    /// <summary>
    /// 解析分页搜索查询条件
    /// </summary>
    public string AnalysePagerWhere(string dataSource)
    {
    StringBuilder sb
    = new StringBuilder();
    Dictionary
    <int, Dictionary<string, string>> 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();
    }

    /// <summary>
    /// 数据源解析接口
    /// </summary>
    public interface IDataAnalyse
    {
    string GetWhere();
    }

    /// <summary>
    /// 解析字符查询
    /// </summary>
    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 OnLoad(EventArgs e)
    {
    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,将基类获取到的查询条件及排序条件带入: 

    /// <summary>
    /// 存储过程分页
    /// </summary>
    public class ProcPager : PagerBase
    {
    protected override void OnLoad(EventArgs e)
    {
    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();
    }
    }

    这样,分页控件已经实现了按前台提交过来的搜索条件对数据进行的过滤。
    最后来改造控件输出及前台页面显示。
    控件输出,在原有的基础上为搜索列头添加搜索属性:

    <asp:Repeater ID="rpList" runat="server">
    <HeaderTemplate>
    <table id="tbList" class="list_table" border="0" cellspacing="0" cellpadding="0">
    <tr>
    <td class="title" style=" 20%;">
    <asp:Label runat="server" columnName="NAME" queryType="text">名称</asp:Label>
    </td>
    <td class="title" style=" 20%;">
    <asp:Label id="Label1" runat="server" columnName="VAL" queryType="text"></asp:Label>
    </td>
    <td class="title" style=" 20%;">
    <asp:Label id="Label2" runat="server" columnName="INT_VAL" queryType="numeric">数值</asp:Label>
    </td>
    <td class="title" style=" 20%;">
    <asp:Label id="Label3" runat="server" columnName="MUTIL_VAL" queryType="values">多选值</asp:Label>
    </td>
    <td class="title" style=" 20%;">
    <asp:Label id="Label4" runat="server" columnName="DATE_VAL" queryType="date">日期</asp:Label>
    </td>
    </tr>
    </HeaderTemplate>
    <ItemTemplate>
    <tr>
    <td><%# Eval("NAME") %></td>
    <td><%# Eval("VAL") %></td>
    <td><%# Eval("INT_VAL")%></td>
    <td><%# Eval("MUTIL_VAL")%></td>
    <td><%# Eval("DATE_VAL")%></td>
    </tr>
    </ItemTemplate>
    <FooterTemplate>
    </table>
    </FooterTemplate>
    </asp:Repeater>
    <ctrl:ProcPager ID="pagerTest" RepeaterId="rpList" PageSize="10" runat="server" />

    前台调用,增加对搜索对象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下载

     
  • 相关阅读:
    【读书笔记-《Android游戏编程之从零开始》】2.Hello,World!
    【读书笔记-《Android游戏编程之从零开始》】1.Android 平台简介与环境搭建
    .Net HttpClient 模拟登录微信公众平台发送消息
    C# DateTime的ToString()方法的使用
    SQL 2008R2 日期转换
    Dojo学习(一)—Hello Dojo
    【博客开篇】服务器配置:Windows2008R2+PHP5.6+SQLServer2008(X64)
    【翻译Autofac的帮助文档】1.入门指南
    申请免费的SSL证书(Win7,PowerShell,Let's Encrypt)
    Rms操作设置office系统文档权限
  • 原文地址:https://www.cnblogs.com/FlySoul/p/2173223.html
Copyright © 2020-2023  润新知