一时兴起用Ajax配合JavaScript写实现自动补全功能的TextBox

 坐了一夜的车终于到家了!这一夜坐车的感觉真的太。。。。。。

还好我的本本比较争气,昨天晚上开节能模式,电池竟然撑了将近三个小时,刚好完成一个能自动补全的TextBox。
下面就描述下过程,希望和有兴趣朋友交流一下优缺点:
开机以后想到离开公司的时候记得MVC的项目中需要一个类似于能够实现自动补全的TextBox,随即打开思路。
需要实现的功能 
1:该控件可以从数据库中读取数据
2:该控件应该在用户更改TextBox中内容时使用Ajax向服务请求相应数据
3:使用Javascript控制从服务请求到的数据的展现方式
4:使用Javascript注册相关事件
嗯  基本功能就是这样了! 那就开始吧!
  启动SQL2008与VS2010后查看了一下可用资源,嗯 还不错数据库中有一个包括全国500多个城市的表(表名:Macaco.CityCollection),这张表有三个字段第一个是AutoID 不用说肯定是自动编号列,第二个是EndNumber 嗯这个比较历害!我也不知道是干什么的 跳过!第三个字段是City里面是城市名。
  VS2010打开后加载了一下我的Demo工程 首先在Tools类库项目下添加了一个数据库表对象属性模型类,其次添加了一个数据库表数据访问类。
代码如下: 
ExpandedBlockStart.gif 数据表对象属性模型类
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

namespace  Macaco.Demo.Tools
{
    
public   class  CityModel
    {
        
public   int  ID {  get set ; }

        
public   int  EndNumber {  get set ; }

        
public   string  City {  get set ; }
    }
}
ExpandedBlockStart.gif 数据表数据访问类
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Data;
using  System.Data.SqlClient;

namespace  Macaco.Demo.Tools
{
    
public   class  CityCollectionTools
    {

        
// 以下为从数据库中获取城市信息的数据访问方法
         string  strcon  =   " server=.;uid=DemoUser;pwd=DemoUser;DataBase=MacacoOnline; " ;

        
public  List < CityModel >  GetCityDataByEndNumberAndCity( string  sqlPar)
        {
            List
< CityModel >  cityList  =   null ;
            
if  ( string .IsNullOrEmpty(sqlPar))
                
return  cityList;

            
// 此处我们以模糊查询的方法查询前10条符合条件的记录  此处以ID排序实际应用中应该要有一个优先级的字段并以此字段排序
             string  strcmd  =   " select top 10 ID,EndNumber,City from Macaco.CityCollection where EndNumber like '%'+@SqlPar+'%' or City like '%'+@SqlPar+'%' order by ID " ;

            SqlCommand sqlcmd 
=   new  SqlCommand(strcmd,  new  SqlConnection(strcon));

            sqlcmd.Parameters.Add(
new  SqlParameter( " @SqlPar " , SqlDbType.VarChar,  20 )).Value  =  sqlPar;

            SqlDataReader sdr 
=   null ;
            
try
            {
                sqlcmd.Connection.Open();
                sdr 
=  sqlcmd.ExecuteReader();
                cityList 
=   new  List < CityModel > ();
                CityModel cityData 
=   null ;
                
while  (sdr.Read())
                {
                    cityData 
=   new  CityModel()
                    {
                        ID 
=  (sdr[ 0 ==   null   ?  cityData.ID : sdr.GetInt32( 0 )),
                        EndNumber 
=  (sdr[ 1 ==   null   ?  cityData.EndNumber : sdr.GetInt32( 1 )),
                        City 
=  (sdr[ 2 ==   null   ||   string .IsNullOrEmpty(sdr.GetString( 2 ))  ?  cityData.City : sdr.GetString( 2 ))
                    };
                    cityList.Add(cityData);
                }
            }
            
finally
            {
                
if  (sdr  !=   null   &&   ! sdr.IsClosed)
                    sdr.Close();

                
if  (sqlcmd.Connection.State  ==  ConnectionState.Open)
                    sqlcmd.Connection.Close();
            }
            
return  cityList;
        }
    }
}

 

   现在需要一个可以响应客户端Ajax请求的程序处理文件,所以我们要在MVC项目添加一个一般事件处理程序命名为GetCityData.ashx(后缀名为.ashx的文件)咦 怎么 这文件有点不对啊 多了一个GetCityData.ashx.cs文件 以前aspx中没有这个文件 算了不管它了,如果不行再说吧(事实证明可以和以前一样使用)! 我把它放到了站点根目录下的一个叫AjaxHelp(自己建的)的文件夹中 然后在里面

添加如下代码:

ExpandedBlockStart.gif 用于响应Ajax请求的一般事件处理程序
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Web;
using  Macaco.Demo.Tools;
using  System.Text;

namespace  Macaco.Demo.MvcWeb.AjaxHelp
{
    
///   <summary>
    
///  获取城市信息的Http管道
    
///   </summary>
     public   class  GetCityData : IHttpHandler
    {
        
public   void  ProcessRequest(HttpContext context)
        {
            
// 清除缓冲区中的所有内容输出
            context.Response.Clear();
            
// 创建数据访问对象
            CityCollectionTools ccTools  =   new  CityCollectionTools();
            
// 声明变量用于存放从URL中取得的参数
             string  strPar  =   null ;
            
try
            {
                
// 获取URL中的参数
                strPar  =  context.Request.QueryString[ 0 ];
            }
            
catch
            {
                
// 若出现异常向客户端响应一个空的输出并终止该方法
                context.Response.Write( "" );
                
return ;
            }
            
// 获取数据库中的数据
            List < CityModel >  cityData  =  ccTools.GetCityDataByEndNumberAndCity(strPar);

            
// 创建一个可变长度的字符串
            StringBuilder sbCityData  =   new  StringBuilder();

            
// 遍历获取到的数据拼接成一个字符串
             foreach  (CityModel city  in  cityData)
            {
                sbCityData.Append(
" <p>( "   +  city.EndNumber  +   " "   +  city.City  +   " </p> " );
            }

            
// 响应客户端输出
            context.Response.Write(sbCityData);
        }

        
///   <summary>
        
///  该属性指示其他请求是否可以与当前请求共享当前的IHttpHandler实例  此属性与我们现的的操作没有关系 默认即可
        
///   </summary>
         public   bool  IsReusable
        {
            
get
            {
                
return   false ;
            }
        }
    }
}

    这段代码主要功能是通过之前添加的数据库表数据访问类中的GetCityDataByEndNumberAndCity方法从数据库模糊查询相应数据并对数据进行简单的格式处理。最后以Response.Write方式响应客户端的请求至此服务端的功能代码基本上就完成了!

   现在我们开始添加客户端的功能代码!在此向大家呼吁一下生活中应该注意环保,懂得资源利用才好(我就不在新建文件了 使用的是MVC项目Home下的Index)!首先在MVC项目下找到Index页面(具体路径应该是:Views/Home/Index.aspx),打开后

添加如下代码:

ExpandedBlockStart.gif 客户端功能-前台页面Index
<% @ Page Language = " C# "  MasterPageFile = " ~/Views/Shared/Site.Master "  Inherits = " System.Web.Mvc.ViewPage "   %>

< asp:Content  ID ="Content1"  ContentPlaceHolderID ="TitleContent"  runat ="server" >
    主页
</ asp:Content >
< asp:Content  ID ="Content2"  ContentPlaceHolderID ="MainContent"  runat ="server" >
    
<% -- 这是MVC中添加TextBox控件的方法等同与  < input id = " txtCity "  name = " txtCity "  value = "" />-- %>
    
<% : Html.TextBox( " txtCity " %> < br  />
    
<% -- 这就是数据的舞台 从服务获取到的数据都会在这个DIV中展现 -- %>
    
< div  id ="ShowDataDiv"  class ="showDataDivStyle"  title ="txtCity" >
    
</ div >
    
    
<% -- 以下这段JS是要向文档的Head标中添加一个Js文件的链接 -- %>
    
< script  type ="text/javascript"  language ="javascript" >
        
// 获取当前文档中Head标记
         var  head  =  document.getElementsByTagName( " head " )[ 0 ];
        
// 创建一个script标记
         var  script  =  document.createElement( " script " );
        
// 设置相关属性
        script.src  =   " Scripts/MacacoJSTools.js " ;
        script.type 
=   " text/javascript " ;
        
// 追加到Head开始标记之后结束标记之前的位置
        head.appendChild(script);
    
</ script >
    
< div  style ="background: silver; margin: 0px; padding: 0px;" >
        
< b >
            
<% : ViewData[ " Message " %> </ b >
        
< p >
            若要了解有关 ASP.NET MVC 的更多信息,请访问 
< href ="http://asp.net/mvc"  title ="ASP.NET MVC 网站" > http://asp.net/mvc </ a >
        
</ p >
    
</ div >
</ asp:Content >

    前台页面就是这样,需要注意的是我在页面中使用JS脚本引入了下面即将要写的JS文件。现在我们要添加一个Js文件我把它放在根目录下的Scripts文件夹下并命名为MacacoJsTools.js并在里面添加了包括创建 发送 响应 Ajax请求以及TextBox控件 P标记 Div标记 的事件绑定的代码 呵呵 这次比较多一点 不过基本上每一句都有注释或提示

详细代码如下 :

ExpandedBlockStart.gif MacacoJsTools.js详细代码如下
// 封装documnet.getElementById方法
function  $(tarGetID) {  return  document.getElementById(tarGetID); }

// 获取操作区域
var  showDataDiv  =  $( " ShowDataDiv " );

// 获取TextBox控件的引用(注:title是TextBox控件的ID)
var  controlInpputID  =  $(showDataDiv.title);

// 设置初始状态为不可见(隐藏)
showDataDiv.style.display  =   " none " ;

// 为TextBox控件注册事件
controlInpputID.onkeyup  =   function  () { SendRequest( this .value) };
controlInpputID.onclick 
=   function  () { SendRequest( this .value) };
controlInpputID.onblur 
=   function  () { // 注:此处注册的事件是当TextBox失去焦点时为在150毫秒调用一个匿名方法把显示数据的DIV隐藏
    setTimeout( function  () {
        showDataDiv.style.display 
=   " none " ;
    }, 
150 )
};

// 创建XMLHttpRequest对象实例
function  GetXMLHttpRequest() {
    
// 声明对象用于指XMLHttpRequest(创建成功指向XMLHttpRequest,失败指向一个bool类型值)
     var  Http_Request  =   false ;

    
// 根据浏览器创建不同的对象实例
     if  (window.XMLHttpRequest) {

        
// 创建基于Mozilla浏览器的XMLHttpRequest对象实例
        Http_Request  =   new  XMLHttpRequest();

        
// 判断请求类型是否有默认设置
         if  (Http_Request.overrideMimeType) {

            
// 若无默认设置则设置为text/xml格式
            Http_Request.overrideMimeType  =   " text/xml " ;
        }
    } 
else   if  (window.ActiveXObject) {
        
// 创建基于IE浏览器XMLHttpRequest的对象实例
         try  {

            
// 创建针对较新版本IE浏览器的XMLHttpRequest对象实例
            Http_Request  =   new  ActiveXObject( " Msxml2.XMLHTTP " );

        } 
catch  (e) {

            
try  {

                
// 创建针对较旧版本IE浏览器的XMLHttpRequest对象实例
                Http_Request  =   new  ActiveXObject( " Microsoft.XMLHTTP " );

            }
            
catch  (e) {

                alert(
" 您的浏览器不支持Ajax的处理操作,无法正常协助您完成查询操作! " );

            }
        }
    }

    
// 返回导步请求处理对象
     return  Http_Request;
}

// 创建全局导步应用处理对象
var  httpRequst;

function  SendRequest(strPar) {
    
if  (strPar.length  >   0 ) {

        
// 获取并赋值全局异步应用处理对象
        httpRequst  =  GetXMLHttpRequest();

        
// 判断是否创建成功
         if  (httpRequst) {

            
// 指定状态更改后的操作
            httpRequst.onreadystatechange  =  ResponseHttpRequest;


            
var  url  =   " /AjaxHelp/GetCityData.ashx? "   +  encodeURI(strPar);


            
// 打开发送请求,指定方式及要请求的文件以及是否为异步调用
            httpRequst.open( " GET " , url,  true );

            
// 发送请求
            httpRequst.send( null );
        }
    } 
else
        showDataDiv.style.display 
=   ' none ' ;
}


// 创建用于响应请求结果的方法
function  ResponseHttpRequest() {

    
if  (httpRequst.readyState  ==   4 ) {

        
// 判断是否正确响应
         if  (httpRequst.status  ==   200 ) {

            
// 判断要操作的DIV是否获取到
             if  (showDataDiv  !=   null ) {
                
var  reqText  =  httpRequst.responseText;
                
// 判断是否查询到数据如果查询到的数据较少则为不正常应将显示数据的DIV隐藏
                 if  (reqText.length  >   10 ) {

                    
/* 将获取的文本添加到要显示数据的DIV中(注:此处不使用innerText是因为Firefox不完全支持该属性
                    (详细可以参考http://www.google.com.hk/)并且请求的数据中包括了HTML标记而我需要这些HTML标记
                    被浏览器解析并应用样式)
*/
                    showDataDiv.innerHTML 
=  reqText;

                    
// 获取DIV中所有的p村记即上面添加进去的HTML标记
                     var  pCol  =  showDataDiv.getElementsByTagName( " p " );

                    
// 使用循环遍历所有P标记为其添加对应的事件与属性
                     for  (i  =   0 ; i  <  pCol.length; i ++ ) {
                        
// 当用户点击某个P标记时则将该P标记内的内容放入TextBox控件中并将DIV隐藏
                        pCol[i].onclick  =   function  () { controlInpputID.value  =   this .innerHTML; showDataDiv.style.display  =   " none " ; }
                        
// 设置用户将鼠标悬停在当前P标记上时显示提示信息即P标记中的所有内容
                        pCol[i].title  =  pCol[i].innerHTML;
                    }
                    
// 显示从服务获取到的数据
                    showDataDiv.style.display  =   " block " ;
                }  else  {
                    
// 如果没有获取到数据隐藏DIV
                    showDataDiv.style.display  =   " none " ;
                }
            }
        }
    }
}

   到此JS的脚本我们就写完了 现在我们还需要为我们的自动补全控件添加一点样式(当然还有一个至关重要属性控制),添加一个CSS文件放到根目录下Content文件夹中我将其命名为MacacoStyleSheet.css 

 添加如下代码: 

ExpandedBlockStart.gif 控制TextBox与Div样式的样式表MacacoStyleSheet.css
.showDataDivStyle
{
    width
:  202px ;
    height
:  210px ;
    line-height
:  15px ;   /* 该属性用于将DIV从内存流中拖出打破原有的样式 */
    position
:  absolute ;
    background-color
:  #ffeeee ;
    font-size
:  12px ;
    border
:  1px solid silver ;   /* 让Div与TextBox更亲近一点 */
    margin-top
:  -1px ;
}
.showDataDivStyle p
{
    cursor
:  pointer ;
    width
:  190px ;
    border
:  1px solid #ffeeee ;
    border-left
:  none ;
    border-right
:  none ;
    margin
:  0px auto ;
}
/* 以下是设置鼠标悬停在P标记上时的样式 */
.showDataDivStyle p:hover
{
    border
:  1px solid blue ;
    border-left
:  none ;
    border-right
:  none ;
    background-color
:  Purple ;
}

   至此所有的代码都已经完成了 现在只需要将该CSS文件的引用添加到页面中就可以测试了 我已经在 IE8,IE9,Safari,遨游3,Opera,Chrome,Firefox 4.0 Beta8测试过 除了Firefox 反应稍微慢1秒左右 其它都可以算的上是完美兼容!唯一遗憾的是 我用的是Win7 IECollection装不了所以IE8以下的浏览器没有测试过,估计在IE6下会有点样式上的偏移,不过判断一下浏览器的版本就可以解决! 如果有朋友在IE6下测试该段代码 请将结果粘到回复中 同时我在上面也有提出一些疑问(例如:为什么MVC项目中的一般事件处理程序为什么要比aspx中的多一个以.cs后缀的文件) 如果有朋友知道在回复中解释一下 谢谢!

可以能过链接下载  项目源码 我已经将Tools项目中的代码文放到了App_Code中项目数据库文件放到了App_Data中您可能需要附加到MSSQL中才可以运行!

 

转载于:https://www.cnblogs.com/macacoonline/archive/2011/01/17/1936902.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值