• 仿Google的输入下拉提示框 (转)


    当我们在使用Google或百度搜索引擎时,当你在搜素框中输入一个关键词的前一个或几个字母/汉字,会发现它们会自动把相关的关键词给列出来,如下图所示,非常人性化:
    Goolge输入下拉框.img.MoFun.CC

      下面,我们就提供了 4 种实现这样效果的方式供您参考:

    一、使用RADComboBox控件来实现:(作者:MoFun.CC)
    <table>
      <tr><td>所属部门</td>
             <td><telerik:RadComboBox ID="rcb_MoFun_CC_Department" Runat="server" CssClass="ColumnLeftInput" Width="130px" DataSourceID="test" MarkFirstMatch ="true" DataTextField="department" DataValueField="Id" HighlightTemplatedItems="True" ShowToggleImage="False" Filter="StartsWith" ShowDropDownOnTextboxClick="False" EnableLoadOnDemand="True">               
                <CollapseAnimation Type="OutQuint" Duration="200"></CollapseAnimation>
                </telerik:RadComboBox>
             </td>
    </tr></table>

    二、自己从头实现:(作者:flywe)

    2.1、.ASCX控件页面:
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="Suggest.ascx.cs" Inherits="Suggest" %>
      
      <style type="text/css">
      
      .pnlSuggest
      {
         border: #000000 1px solid;
         background-color: #FFFFFF;
         z-index: 9527;
         position: absolute;
         overflow-y: auto;
         overflow-x: hidden;
         text-overflow: clip;
      }
      
    .pnlSuggest table
    {
         100%;
    }

    .pnlSuggest tr
    {
         100%;
    }

    .trmouseover
    {
         100%;
         background-color: #397CC3;
    }

    .trmouseover td
    {
         text-align: left;
         overflow: hidden;
         text-overflow: clip;
         background-color: #397CC3;
    }

    .trmouseout
    {
         100%;
         background-color: #FFFFFF;
    }

    .trmouseout td
    {
         text-align: left;
         overflow: hidden;
         text-overflow: clip;
         background-color: #FFFFFF;
    }

    .txtValues
    {
         display: none;
    }

    .dataSource
    {
         display: none;
    }

    .hiddentd
    {
         display: none;
    }

    .hiddenValues
    {
         display: none;
    }

    </style>

    <script language="javascript" type="text/javascript">

    //为string对象添加一个清除前后空格的属性
    String.prototype.trim = function()
    {
         return this.replace(new RegExp("(^[\\s]*)|([\\s]*$)", "g"), "");
    };

    //显示下拉信息
    function ShowSuggest(objInputText)
    {
         objInputText.onkeyup = ControlSuggest;
        
         objInputText.onblur = RemoveSuggest;
        
         var oldValue = objInputText.parentElement.getElementsByTagName("h6")[0];
        
         //对提示框的控制
         function ControlSuggest()
         {
             var ie = (document.all)?true:false;
             if(ie)
             {
                 var keycode = event.keyCode;
                var txtvalues = objInputText.value.trim().split(";");
                
                if( !CheckSuggest() && txtvalues[txtvalues.length-1] != oldValue.innerText.trim())
                {
                    CreateSuggest();
                    return ;
                }
                
                if(keycode == 32 && txtvalues[txtvalues.length-1] != oldValue.innerText.trim())
                {
                    CreateSuggest();
                    return ;
                }
                
                //按向下创建提示
                if(!CheckSuggest() && txtvalues[txtvalues.length-1].length !=0 && keycode == 40)
                {//文本框有内容,提示不存在,向下
                    CreateSuggest();
                    return;
                }
                
               //当删除的时候,参量要初始化
                if(keycode == 8 && txtvalues[txtvalues.length-1].length == 0)
                {
                    DeleteSuggest();
                    oldValue.innerText = "";
                    return ;
                }
                
                if(CheckSuggest())
                {
                    var inputIndex = document.getElementById("inputIndex");
                    var selectIndex = Number(inputIndex.value);
                    
                    //排除上下控制的值操作外,其他任何值改变都要去创建提示框
                    if( selectIndex < 0 && txtvalues[txtvalues.length-1] != oldValue.innerText)
                    {
                        CreateSuggest();
                        return ;
                    }
                    
                    if(keycode == 40)
                    {//向下
                        ChangeSelection(false);
                        return ;
                    }
                    
                   if(keycode == 38)
                    {//向上
                        ChangeSelection(true);
                        return ;
                    }
                    
                    if(keycode == 46 || keycode == 27)
                    {//del
                        DeleteSuggest();
                        oldValue.innerText = "";
                        return ;
                    }
                    
                    var panelSuggest = document.getElementById("divSuggestPanel");
                    var tb = panelSuggest.getElementsByTagName("table")[0];

                    if(keycode == 13)
                    {//回车
                        if(selectIndex > -1 && txtvalues[txtvalues.length-1] != oldValue.innerText)
                        {
                            CreateSuggest();
                            return ;
                        }
                        RemoveSuggest();
                        return ;
                    }
                    
                }
                
                if(txtvalues[txtvalues.length-1] != oldValue.innerText)
                {//当上面的条件都筛选后,只要值发生改变就创建下拉提示
                    CreateSuggest();
                    return ;
                }
            }
        }
        
        //删除提示前对文本做相关操作
        function RemoveSuggest()
        {
            if(CheckSuggest())
            {
                var panelSuggest = document.getElementById("divSuggestPanel");
                var inputIndex = document.getElementById("inputIndex");
                
                var txtvalues = objInputText.value.trim().split(";");
                
                if( CheckActiveElement(panelSuggest) || event.keyCode == 13)
                {
                    //做个判断,判断当前活动对象 是不是TD,是的话就执行下面的操作,不是的话就不做操作,或者把文本框作为当前活动
                    if(CheckActiveElement(panelSuggest) && document.activeElement.tagName != "TD")
                    {
                        objInputText.focus();
                        return ;
                    }
                    
                    //得到选定的值
                    var selectIndex = Number(inputIndex.value);
                    if(selectIndex >= 0)
                    {
                        var tb = panelSuggest.getElementsByTagName("table")[0];
                        txtvalues[txtvalues.length-1] = tb.rows[selectIndex].cells[0].innerText;
                        objInputText.value = GetValues(txtvalues);
                    }
                }
                
                document.body.removeChild(inputIndex);
                document.body.removeChild(panelSuggest);
                oldValue.innerText = "";
            }
            else
            {
                return ;
            }
        }
        
        //删除提示的方法,不对文本做任何操作
        function DeleteSuggest()
        {
            if(CheckSuggest())
            {
                var panelSuggest = document.getElementById("divSuggestPanel");
                var inputIndex = document.getElementById("inputIndex");
                document.body.removeChild(inputIndex);
                document.body.removeChild(panelSuggest);
            }
        }
        
        //加载提示框
        function CreateSuggest()
        {
            var txtvalues = objInputText.value.trim().split(";");
            
            //提示框存在,而且文本框值与上次的输入不同时,才进行下面的加载工作
            if(CheckSuggest())
            {
                if( oldValue.innerText.trim() == txtvalues[txtvalues.length-1].trim())
                {
                    return ;
                }
                else
                {
                    DeleteSuggest();
                }
            }
            
            if(CheckSuggest() && txtvalues[txtvalues.length-1].trim().length ==0)
            {//提示框存在,但是文本框没有内容,这时删除提示框
                DeleteSuggest();
                oldValue.innerText = "";
                return ;
            }
            
            //如果输入为空格,就退出
            if(txtvalues[txtvalues.length-1].trim().length == 0)
            {
                return ;
            }
            
            //从数据源中取数据
            var suggestList = GetSuggestList();
            
            if(suggestList == null||suggestList.length < 1)
            {//对传入的数组进行判断,为空或者列表为0就退出
                DeleteSuggest();                                  //开始的输入有提示,后面的输入可能没有提示,所以数据源为空时要尝试删除提示
                oldValue.innerText = "";
                return ;
            }
            
            oldValue.innerText = txtvalues[txtvalues.length-1];              //以上条件都符合,根据数据源来创建数据
            
            var inputIndex = document.createElement("input");     //用隐藏控件来做索引的保存
            inputIndex.type = "hidden";
            inputIndex.id = "inputIndex";
            inputIndex.value = -1;
            
            var suggest = "";                                     //根据数据源来写div提示信息
            suggest += "<table>";
            for(var nIndex = 0; nIndex < suggestList.length; nIndex++)
            {
                suggest += "<tr onmouseover=\" for(var n=0;n<this.parentElement.rows.length;n++){this.parentElement.rows[n].className='trmouseout';};this.className='trmouseover';var inputIndex = document.getElementById('inputIndex');inputIndex.value = this.rowIndex; \" onmouseout=\"this.className='trmouseout';\"  >";
                suggest += suggestList[nIndex];
                suggest += "</tr>";
            }
            suggest += "</table>";
            
            var panelSuggest = document.createElement("div");                //创建装提示框的容器div
            
            panelSuggest.id = "divSuggestPanel";
            panelSuggest.className = "pnlSuggest";                           //设置对象的类
            panelSuggest.style.width = objInputText.clientWidth + "px";      //设置对象的宽度,与文本框宽度相同
            panelSuggest.style.top = (GetPosition()[0] + objInputText.offsetHeight + 1) + "px";
            panelSuggest.style.left = GetPosition()[1] + "px";
            panelSuggest.innerHTML = suggest;
            
            document.body.appendChild(panelSuggest);                         //把提示框和索引控件添加进来        
            document.body.appendChild(inputIndex);
            
            //判断显示条数的多少,多于10条就用滚动条操作
            if(suggestList.length > 10)
            {
                var h = panelSuggest.getElementsByTagName("tr")[1].offsetHeight;
                panelSuggest.style.height = (h * 10) + "px";
                panelSuggest.style.width = (objInputText.clientWidth + 20) + "px";
            }
            
        }
        
        //更换选项
        function ChangeSelection(isup)
        {

            if(CheckSuggest())
            {
                var txtvalues = objInputText.value.trim().split(";");
                
                var inputIndex = document.getElementById("inputIndex");                 //得到索引的值
                var selectIndex = Number(inputIndex.value);
                
                var panelSuggest = document.getElementById("divSuggestPanel");          //得到提示框
                var tb = panelSuggest.getElementsByTagName("table")[0];
                var maxIndex = tb.rows.length - 1;                                      //提示信息的最大索引
                
                if(isup)
                {//向上
                    if(selectIndex >= 0)                                                //索引不能为负
                    {
                        tb.rows[selectIndex].className = "trmouseout";
                        selectIndex--;
                        if(selectIndex >= 0)
                        {
                            tb.rows[selectIndex].className = "trmouseover";
                        }
                    }
                }
                else
                {
                    if(selectIndex < maxIndex)                                          //大于等于最大索引就不做任何操作
                    {
                        if(selectIndex >= 0)
                        {
                            tb.rows[selectIndex].className = "trmouseout";
                        }
                        selectIndex++;
                        tb.rows[selectIndex].className = "trmouseover";
                    }
                }
                
                inputIndex.value = selectIndex;
                //控制滚动条的上下
                if(selectIndex >= 0)
                {
                    if(tb.rows[selectIndex].offsetTop < panelSuggest.scrollTop)
                    {
                        panelSuggest.scrollTop = tb.rows[selectIndex].offsetTop;
                    }
                    if(tb.rows[selectIndex].offsetTop + tb.rows[selectIndex].offsetHeight > panelSuggest.scrollTop + panelSuggest.offsetHeight)
                    {
                        panelSuggest.scrollTop = tb.rows[selectIndex].offsetTop + tb.rows[selectIndex].offsetHeight - panelSuggest.offsetHeight;
                    }
                }
                
            }
            
        }
        
        //判断活动对象是否为obj对象的从属对象
        function CheckActiveElement(obj)
        {
            var isAe = false;
            var objtemp = document.activeElement;
            while(objtemp != null)
            {
                if(objtemp == obj)
                {
                    isAe = true;
                    break;
                }
                objtemp = objtemp.parentElement;
            }
            return isAe;
        }
        
        //检查提示框是否存在
        function CheckSuggest()
        {
            var panelSuggest = document.getElementById("divSuggestPanel");
            if(panelSuggest == null)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        
        //获取文本框的位置
        function GetPosition()
        {
            var top = 0,left = 0;
            var obj = objInputText;
            do
            {
                top += obj.offsetTop;         //距离顶部
                left += obj.offsetLeft;       //距离左边
            }
            while (obj = obj.offsetParent);
            
            var arr = new Array();
            arr[0] = top;
            arr[1] = left;
            return arr;
        }
        
        //得到提示数据
        function GetSuggestList()
        {
            var txtvalues = objInputText.value.trim().split(";");
            var txtfield = txtvalues[txtvalues.length-1];
            var hiddenvaluefield = objInputText.parentElement.getElementsByTagName("h2")[0].innerText;
            var showtextfield = objInputText.parentElement.getElementsByTagName("h3")[0].innerText;
            var procedurename = objInputText.parentElement.getElementsByTagName("h4")[0].innerText;
            var condition = objInputText.parentElement.getElementsByTagName("h5")[0].innerText;
            var suggestlist = Suggest.GetSuggestData(txtfield,showtextfield,procedurename,condition).value;
            return suggestlist;
        }
        
        //得到文本框的显示值
        function GetValues(values)
        {
            var txtvalue="";
            for(var n=0;n<values.length;n++)
            {
                if(values[n].trim().length==0)
                {
                    continue;
                }
                txtvalue+=values[n]+";";
            }
            return txtvalue;
        }
        
    }

    </script>

    <div>
        <input type="text" runat="server" id="txtInput" name="txtInput" onkeydown="ShowSuggest(this);" style=" 320px" autocomplete="off" />
        <h2 id="hneedfield" runat="server" class="hiddenValues"></h2>
        <h3 id="hshowfield" runat="server" class="hiddenValues"></h3>
        <h4 id="hprocedurename" runat="server" class="hiddenValues"></h4>
        <h5 id="hhashvalue" runat="server" class="hiddenValues"></h5>
        <h6 class="hiddenValues" style="display: none;"></h6>
    </div>

    2.2、对应的后端.CS文件:
    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Collections.Generic;
    using System.Data.SqlClient;
    using IIP.Data.SQLHelper;

    /**//// <summary>
    /// 转贴地址 http://www.cnblogs.com/huowujiyx/archive/2008/07/07/1237355.html
    /// 使用说明:调用该控件,要设置控件的相关属性:
    ///           显示提示的筛选字段名 TextField
    ///           查询数据的存储过程名 Procedurename
    ///           存储过程的各项参数   ProcedureParams(Hashtable类型,key值放参数名,value值为参数值)
    ///           还可以通过下面的方法,设置域的值:
    ///           List<string> showFields    要下拉提示的相关信息  AddShowFields(string field)方法添加
    ///           设置好上面的信息后就可以使用了,要得到文本框信息,通过属性Text得到
    ///           要取得与文本信息相匹配的隐藏信息,也就是与hiddenFields对应的信息,通过属性Values得到
    /// </summary>
    public partial class Suggest : System.Web.UI.UserControl
    {
        private string textField;

        /**//// <summary>
        /// 设置要显示提示的筛选字段名
        /// </summary>
        public string TextField
         {
             set { textField = value; }
         }

         private string valueField;

         /**//// <summary>
         /// 设置要得到的唯一性标识的字段名
         /// </summary>
         public string ValueField
         {
             set { valueField = value; }
         }

         private string procedurename;

         /**//// <summary>
         /// 设置查询数据的存储过程名
         /// </summary>
         public string Procedurename
         {
             set { procedurename = value; }
         }

         private Hashtable procedureParams = new Hashtable();

         /**//// <summary>
         /// 设置存储过程的各项参数
         /// </summary>
         public Hashtable ProcedureParams
         {
             set { procedureParams = value; }
         }

         private List<string> showFields = new List<string>();

         /**//// <summary>
         /// 添加显示内容的字段
         /// </summary>
         /// <param name="field">字段名</param>
         public void AddShowFields(string field)
         {
             showFields.Add(field);
         }

         /**//// <summary>
         /// 得到文本框的值
         /// </summary>
         public string Text
         {
             get
             {
                 string[] texts = txtInput.Value.Split(new string[] { ";" }, StringSplitOptions.None);
                 DataTable dt = GetDataSourse(this.hprocedurename.InnerText, this.hhashvalue.InnerText);
                 string txtvalue = "";
                 foreach (string text in texts)
                 {
                     DataRow[] drs = dt.Select(this.hshowfield.InnerText.Split(new string[] { "$h,w$" }, StringSplitOptions.RemoveEmptyEntries)[0] + " = '" + text + "'");
                     if (drs.Length > 0)
                     {
                         txtvalue += text + ",";
                    }
                }
                return txtvalue;
            }
        }

        /**//// <summary>
        /// 得到与文本框值匹配的信息
        /// </summary>
        public string Values
        {
            get
            {
                string[] texts = txtInput.Value.Split(new string[] { ";" }, StringSplitOptions.None);
                DataTable dt = GetDataSourse(this.hprocedurename.InnerText, this.hhashvalue.InnerText);
                string value = "";
                foreach (string text in texts)
                {
                    DataRow[] drs = dt.Select(this.hshowfield.InnerText.Split(new string[] { "$h,w$" }, StringSplitOptions.RemoveEmptyEntries)[0] + " = '" + text + "'");
                    if (drs.Length > 0)
                    {
                        value += drs[0][this.hneedfield.InnerText.Trim()].ToString() + ",";
                    }
                }
                return value;
            }
        }

        /**//// <summary>
        /// 得到数据源
        /// </summary>
        /// <param name="procedurename">存储过程名</param>
        /// <param name="condition">存储过程参数</param>
        /// <returns>查询数据源</returns>
        private DataTable GetDataSourse(string procedurename, string condition)
        {
            //从数据源得到数据
            string[] keyandvalue = condition.Split(new string[] { "$h,w$" }, StringSplitOptions.RemoveEmptyEntries);

            SqlParameter[] commandparameters;
            if (keyandvalue.Length == 0)
            {
                commandparameters = null;
            }
            else
            {
                commandparameters = new SqlParameter[keyandvalue.Length];
                for (int i = 0; i < commandparameters.Length; i++)
                {
                    string[] tempvalue = keyandvalue[i].Split(new string[] { "$h,57,w$" }, StringSplitOptions.None);
                    commandparameters[i] = new SqlParameter(tempvalue[0], SqlDbType.VarChar, 500);
                    commandparameters[i].Value = tempvalue[1];
                }
            }

            DataSet ds = SqlHelper.ExecuteDataset(Comm.connectionString, CommandType.StoredProcedure, procedurename, commandparameters);
            if (ds == null || ds.Tables[0] == null)
            {
                return null;
            }
            else
            {
                return ds.Tables[0];
            }
        }

        /**//// <summary>
        /// 根据输入内容,得到数据
        /// </summary>
        /// <param name="txtfield">显示文本</param>
        /// <param name="showtextfield">下拉提示的相关字段</param>
        /// <param name="procedurename">存储过程名</param>
        /// <param name="condition">存储过程参数</param>
        [Ajax.AjaxMethod]
        public string[] GetSuggestData(string txtfield, string showtextfield, string procedurename, string condition)
        {
           
            //数据的要显示字段和要相关得到数值的字段
            string[] shows = showtextfield.Split(new string[] { "$h,w$" }, StringSplitOptions.RemoveEmptyEntries);

            //数据的筛选
            DataTable dt = GetDataSourse(procedurename, condition);
            if (dt == null)
            {
                return null;
            }
            DataRow[] drs = dt.Select(shows[0] + " like '%" + txtfield + "%'");
            if (drs.Length == 0)
            {
               return null;
            }

            //将数据做为显示流
            List<string> fields = new List<string>();

            for (int j = 0; j < shows.Length; j++)
            {
                fields.Add(shows[j]);
            }

            string[] tbs = new string[drs.Length];
            int count = 0;
            foreach (DataRow dr in drs)
            {
                foreach (string item in fields)
                {
                    tbs[count] += "<td>" + dr[item].ToString() + "</td>";
                }
                count++;
            }
            return tbs;
        }

        /**//// <summary>
        /// 页面的相关信息的保存
        /// </summary>
        private void BindValue()
        {
            //页面中加上与文本输入相关的有下拉提示的字段
            this.hshowfield.InnerText = this.textField;
            int i = 0;
            foreach (string item in showFields)
            {
                this.hshowfield.InnerText += "$h,w$";
                this.hshowfield.InnerText += item;
                i++;
            }

            //页面中加上查询数据源的存储过程
            this.hprocedurename.InnerText = this.procedurename;

            //页面中加上与存储过程匹配的参数
            this.hhashvalue.InnerText = "";
            if (procedureParams != null && procedureParams.Count > 0)
            {
                i = 0;
                foreach (DictionaryEntry temp in procedureParams)
                {
                    if (i != 0)
                    {
                        this.hhashvalue.InnerText += "$h,w$";
                    }
                    this.hhashvalue.InnerText += temp.Key.ToString() + "$h,57,w$" + temp.Value.ToString();
                    i++;
                }
            }

            //唯一标识的字段名
            this.hneedfield.InnerText = this.valueField;
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Ajax.Utility.RegisterTypeForAjax(typeof(SearchText));
            if (!IsPostBack)
            {
                BindValue();
            }
        }
    }
      然后在aspx页面就可以拖这个控件来用,不过在其page_load方法中,要对控件的两个控件的数据源进行设置,不然会因没有数据而不弹出提示框。

    三、使用 JQuery Framework 来实现:
      经笔者亲自测试作者给出的例子,感觉比较强大,且支持 Firefox 2, IE 6 & 7, Opera 9, Safari 3,已完全满足需求,所以 MoFun.CC 推荐您重点考虑这个:
      文档介绍:http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/
      演示地址:http://jquery.bassistance.de/autocomplete/demo/

    四、使用 Suggest Framework 来实现:
      不过这种方式,给出的例子似乎没有下拉项的过滤功能那个能,具体参见:
      http://alex.dojotoolkit.org/shrinksafe/
      http://alex.dojotoolkit.org/shrinksafe/

    http://www.cnblogs.com/rexying/archive/2009/04/29/1445971.html

    http://blog.csdn.net/sandyxxx/archive/2008/02/03/2079690.aspx

    http://blog.csdn.net/CutBug/archive/2009/01/27/3853759.aspx

    http://topic.csdn.net/u/20081025/16/a56b1450-764b-46d9-985c-0aab5e36eb83.html

  • 相关阅读:
    项目管理系列(其他):国际工程承包项目风险识别与分析
    公司注册之简化版
    公司注册之百度百科
    有效投标不足三家不应是重新招标的必要条件
    CPU频率
    集成电路
    晶体管
    Oracle问题之ORA-01609、ORA-00362
    Oracle问题之ORA-12560TNS:协议适配器错误
    Oracle问题之字符集问题,登陆sqlplus出现问号
  • 原文地址:https://www.cnblogs.com/bnuvincent/p/1616465.html
Copyright © 2020-2023  润新知