我平时的软件开发中,信息的搜索是经常碰到的,增加搜索关键字提示是提高用户体验的一种很好的办法。今天就介绍下在ASP.NET如何利用AJAX来实现搜索的信息提示!

 

       1.需要了解的一些知识点

           (1)AJAX对象不同浏览器的创建

                   不同的浏览器对AJAX(XMLHttpRequest)对象的实现是不一样的,例如IE浏览器是通过ActiveX控件来实现AJAX对象。而其他一些浏览器比如火狐,它将AJAX对象实现成了一个浏览器内部的对象叫XMLHttpRequest,所以不同的浏览器创建AJAX对象的方式也就不同,那么我们来看看不同浏览器之间创建AJAX对象的方式:

                   在IE浏览器下面的创建:

        //IE浏览器
        try {
            
//IE5.0

            httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        } 
catch
 (e) {
            
try
 {
                
//IE5.5 以上版本

                httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
        } 
catch (e) { }

   

                   在火狐浏览器下面的创建:

        //火狐, Safari 等浏览器
        httpRequest = new XMLHttpRequest();

                   多浏览器AJAX对象创建函数: 

function createAjaxObj() {
    
var httpRequest = false
;

    
//判断是否包含XMLHttpRequest对象 PS:将来IE高也有可能继承次对象

    if (window.XMLHttpRequest) {
        
//火狐 , Safari 等浏览器

        httpRequest = new XMLHttpRequest();
        
if
 (httpRequest.overrideMimeType)
            httpRequest.overrideMimeType(
'text/xml'
);

    }//判断是否支持Active控件对象
    else if (window.ActiveXObject) {
        
//IE浏览器

        try {
            
//IE5.0

            httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        } 
catch
 (e) {
            
try
 {
                
//IE5.5以上

                httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
        } 
catch
 (e) { }
        }
    }
    
//返回创建好的AJAX对象

    return httpRequest;
}

 

          (2)文本框内容改变的事件在不同浏览器下的使用

                  文本框内容改变的事件目前来说还没有一个标准的版本。我们目前只关心IE与火狐好了,那么在IE和火狐下这两个时间分别怎么表示呢?

                  IE: onpropertychange

           FireFox: oninput

                 那么如何在页面加载时,根据浏览器给文本框附加对应的change事件呢?

                 1.JS如何判断浏览器版本                   

//IE浏览器
if (navigator.userAgent.indexOf("MSIE"> 0)
{ }

//火狐浏览器
if (isFirefox = navigator.userAgent.indexOf("Firefox"> 0)
{}

 

                 2.根据浏览器版本给文本框附加对应事件

function getOs() {
    
//判断浏览器类型 
       if (navigator.userAgent.indexOf("MSIE"> 0) {
        
//此时假设文本框id为'txtSearch'
        //为文本框附加IE所支持的事件
        document.getElementById('txtSearch').attachEvent("onpropertychange", search);
        OsTyep 
= "MSIE";
    } 
else if (navigator.userAgent.indexOf("Firefox"> 0) {
        
//此时假设文本框id为'txtSearch'
        //为文本框附加火狐所支持的事件
        document.getElementById('txtSearch').addEventListener("input", search, false);
        OsTyep 
= "Firefox";
    }
}

                3.根据浏览器版本给文本框清除对应事件

function ClearOS() {
    
if (navigator.userAgent.indexOf("MSIE"> 0) {
        //此时假设文本框id为'txtSearch'
        //为文本框清除IE所支持的事件
        document.getElementById(
'txtSearch').detachEvent("onpropertychange", search);
        OsTyep 
= "MSIE";
    } 
else if (navigator.userAgent.indexOf("Firefox"> 0) {
        //此时假设文本框id为'txtSearch'
        //为文本框清除火狐所支持的事件
        document.getElementById(
'txtSearch').removeEventListener("input", search, false);
        OsTyep 
= "Firefox";
    }
}

 

       2.客户端的设计

           (1)实现流程的分析

                   了解完以上知识点之后,我们来看一下实现搜索提示的一个整体流程:

                   (1) 首先客户端通过文本框输入事件捕获输入的关键字

                   (2)  在通过我们之前创建好的AJAX对象提交给服务器

                   (3) 服务器接受提交的关键字,进行查询将结果集返回给客户端进行显示

                    流程如下:

           (2)样式的编写

                   那么接下来我们来看一下样式,其中包括当文本框鼠标移动上去给边框加颜色与搜索结果行选中的样式等,这里就不细说了,列举出来供参考:

 <style type="text/css" media="screen">
    body
    
{
        font
:11px arial;
    
}
    
/*设置提示提示列表上的样式表*/
    .search_link
    
{         
         background-color
:#FFFFFF;
         cursor
: pointer;
         line-height
:24px;
         text-indent
:6px;
    
}
    
/*设置当鼠标移动到提示列表上的样式表*/
    .search_link_over
    
{     
         background-color
:#E8F2FE;
         cursor
: pointer;
         line-height
:24px;
         text-indent
:6px;

    
}
    
    
/*设置显示搜索提示div的样式表*/
    #search_div
    
{
        position
:absolute;
        background-color
:#FFFFFF;
        text-align
:left;
        border
:1px solid #000000;
        border-top
:0px;
        display
:none;
        min-width
:553px;
        width
:553px;
    
}
    
    
/*文本框样式*/
    .mainInput  
{
    line-height
: 26px;
    height
: 28px;
    width
: 550px;
    font-size
: 16px;
    font-family
: "微软雅黑", "宋体", Candara;
    font-weight
: normal;
    color
: #666;
    margin
: auto;
    border
: none;
    text-indent
: 8px;
}
    
    
/*鼠标放上文本框样式*/
    .mainInputOver  
{
    width
:552px;
    height
:30px;
    border-top-width
: 1px;
    border-right-width
: 1px;
    border-bottom-width
: 1px;
    border-left-width
: 1px;
    border-top-style
: solid;
    border-right-style
: solid;
    border-bottom-style
: solid;
    border-left-style
: solid;
    border-top-color
: #b7b7b7;
    border-right-color
: #d0d0d0;
    border-bottom-color
: #d0d0d0;
    border-left-color
: #d0d0d0;
}
/*鼠标离开文本框样式*/
.mainInputFocus  
{
    width
:552px;
    height
:30px;
    border
: 1px solid #41b5f2;
}

/*点击文本框样式*/
.myBorder
{
    width
:552px;
    height
:30px;
    border-top
: 1px solid #CCCCCC;
    border-bottom
: 1px solid #DDDDDD;
    border-left
: 1px solid #DDDDDD;
    border-right
: 1px solid #DDDDDD;    
}
    </style>

 

           (3)aspx页面与ajax_search.js文件的编写

                   接下来就是一个比较重要的环节了,aspx页面与ajax_search.js文件中包含了整体包括显示与请求的方法例如:

                    1.页面的实现

<body onload="getOs()" onkeydown="if(event.keyCode==13)return false;">
    
<form id="form1" runat="server">
    
<div>
    
<div class="myBorder" onmouseover="this.className='mainInputOver'" onmouseout="this.className='myBorder'"  onclick="this.className='mainInputFocus'">
    
<input type="text" id="txtSearch"  name="txtSearch" onblur="HiddenDiv()" alt="SearchCriteria" autocomplete="off" class="mainInput"  />
    
</div>
    
<!--该DIV作为现实搜索提示的结果-->
    
<div id="search_div" style="margin-top:0px" ></div>
    
</div>
    
</form>
</body>

                    2.根据浏览器创建AJAX对象

var searchReq = createAjaxObj();
var OsTyep = '';

function getOs() {
    
//判断浏览器类型 
    if (navigator.userAgent.indexOf("MSIE"> 0) {
        document.getElementById(
'txtSearch').attachEvent("onpropertychange", search);
        OsTyep 
= "MSIE";
    } 
else if (navigator.userAgent.indexOf("Firefox"> 0) {
        document.getElementById(
'txtSearch').addEventListener("input", search, false);
        OsTyep 
= "Firefox";
    }
}

function ClearOS() {
    
if (navigator.userAgent.indexOf("MSIE"> 0) {
        document.getElementById(
'txtSearch').detachEvent("onpropertychange", search);
        OsTyep 
= "MSIE";
    } 
else if (navigator.userAgent.indexOf("Firefox"> 0) {
        document.getElementById(
'txtSearch').removeEventListener("input", search, false);
        OsTyep 
= "Firefox";
    }
}

function createAjaxObj() {
    
var httpRequest = false;

    
//判断是否包含XMLHttpRequest对象 PS:将来IE高也有可能继承次对象
    if (window.XMLHttpRequest) {
        
//火狐 , Safari 等浏览器
        httpRequest = new XMLHttpRequest();
        
if (httpRequest.overrideMimeType)
            httpRequest.overrideMimeType(
'text/xml');

        
//ie: onpropertychange
        //ff: oninput
    } //判断是否支持Active控件对象
    else if (window.ActiveXObject) {
        
//IE浏览器
        try {
            
//IE5.0
            httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        } 
catch (e) {
            
try {
                
//IE5.5以上
                httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
            } 
catch (e) { }
        }
    }
    
//返回创建好的AJAX对象
    return httpRequest;
}

                    3.创建请求与返回数据的显示

//异步请求服务器获取搜索结果
function search() {
    
if (searchReq.readyState == 4 || searchReq.readyState == 0) {
        
//获得文本框中的值
        var valStr = escape(document.getElementById("txtSearch").value);
        
//建立连接
        searchReq.open("GET", encodeURI('Search.ashx?search=' + valStr+'&fresh=' + Math.random()), true);
        
//当请求状态改变时调用 handleSearch方法
        searchReq.onreadystatechange = handleSearch;
        searchReq.send(
null);
    }
}

//返回结果处理方法
function handleSearch() {
    
if (searchReq.readyState == 4) {
        
//获得搜索提示结果的元素DIV
        var searchDIV = document.getElementById("search_div");
        searchDIV.innerHTML 
= "";

        
//用^将返回的文本数据分割成数组
        var resultStrArr = searchReq.responseText.split("^");

        
//循环构建HTML代码
        for (var i = 0; i < resultStrArr.length - 1; i++) {
            
var htmlStr = '<div onmouseover="selectOverDiv(this,'+i+');" ';
            htmlStr 
+= 'onmouseout="selectOutDiv(this,'+i+');" ';
            htmlStr 
+= 'onclick="setSearch(this.innerHTML);" ';
            htmlStr 
+= 'class="search_link " style="display:block;width:100%;" >' + resultStrArr[i] + '</div>';

            searchDIV.innerHTML 
+= htmlStr;
        }
        ShowDiv();
        x 
= -1;
    }
}

                    4.将数据选中数据显示文本框中

                       上边代码中在循环构建HTML代码时,我们给构建的DIV加入了三个事件分别是:

                        1 onmouseover="selectOverDiv(this,'+i+');" 

                           当鼠标放上去时调用selectOverDiv函数传递自己进去

                        2 onmouseout="selectOutDiv(this,'+i+');" 

                           当鼠标放上去时调用selectOutDiv函数传递自己进去

                        3 onclick="setSearch(this.innerHTML);" 

                           当鼠标点击DIV时调用setSearch函数传入本身DIV中内容

                     那么还是来看下这几个方法的实现吧:

function selectOverDiv(div_value, i) {   
    div_value.className 
= "search_link_over"
;
    
var my_div = document.getElementById("search_div").getElementsByTagName("div"
)
    
var the_num =
 my_div.length;
    
for (var k = 0; k < the_num; k++
) {
        selectOut(my_div[k]);
        
if (k ==
 i) {
            selectOver(my_div[k])
        }
    }
    isCheckDiv 
= true
;
    x 
=
 i;
}

function selectOutDiv(div_value,i) {
    isCheckDiv 
= 
false;
    div_value.className 
= "search_link
";
    x 
= i;
}

function
 setSearch(value) {
    
//清空文本框的内容改变事件是因为我们给选中值复制时 该事件会触发 

    //所以先清空次事件
    ClearOS();
    document.getElementById(
"txtSearch").value =
 value;
    
//设置该属性为false 在调用HiddenDiv函数会隐藏提示结果DIV

    isCheckDiv = false
    HiddenDiv();
    
//在赋值完成后再次附加修改时间

    getOs();
}

function
 ShowDiv() {
    
var content = document.getElementById("txtSearch"
).value;
    
var divConten = document.getElementById("search_div"
).innerHTML;
    
if (content != '' && divConten != ''
) {
        document.getElementById(
"search_div").style.display = "block"

    } 
else {
    isCheckDiv 
= false
;
    HiddenDiv();
    }
    
}
function
 HiddenDiv() {
    
if (isCheckDiv == false
) {
        document.getElementById(
"search_div").style.display = "none"
;
        document.getElementById(
"search_div").innerHTML = ''
;
    }
}

                    5.增加键盘上下键选中提示数据与回车键选中数据到文本框

var index = -1//表示当前选中的行索引
function keyDown() {
    
var value = event.keyCode
    
//向上38,向下40,回车13
    var the_key = event.keyCode 
    
//判断提示DIV是否是现实状态
    if (document.getElementById("search_div").style.display != "none") {
        
//获取里面所用行
        var my_div = document.getElementById("search_div").getElementsByTagName("div")
        
var the_num = my_div.length;
        
switch (the_key) {
            
case 40//向下
                //判断index是否已经到最下面
                if (index == the_num - 1) {
                    index 
= 0;
                } 
else {
                    index
++;
                }
                
//清楚所有选中
                for (var i = 0; i < the_num; i++) {
                    selectOut(my_div[i]);
                }
                
//根据index选中对应索引行
                for (i = 0; i < the_num; i++) {
                    
if (i == index) {
                        selectOver(my_div[i])
                    }
                }
                
break;
            
case 38//向上
                //判断index是否已经到最上面
                if (index == 0) {
                    index 
= the_num-1;
                } 
else { index--; }
                
//清楚所有选中
                for (var i = 0; i < the_num; i++) {
                    selectOut(my_div[i]);
                }
                
//根据index选中对应索引行
                for (i = 0; i < the_num; i++) {
                    
if (i == index) {
                        selectOver(my_div[i])
                    }
                }
                
break;
            
case 13//回车
                //将选中的内容放入文本框中
                if (my_div[index].innerHTML != null) {
                    setSearch(my_div[index].innerHTML);
                }
                
break;
        }

    }

}
document.onkeydown 
= keyDown;

 

       3.服务器端的设计

           (1)实现一个虚拟的数据源

                 前台传来关键字,后台必须要有数据匹配,为了简单我就不建立数据库了 我就模拟一个数据源好啦!

              步骤:右键项目 --> 添加新项--> 选择一般处理程序命名为:Search.ashx 编写代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.CodeDom;
using System.Globalization;
using System.ComponentModel;
using System.Collections;

public class Search : IHttpHandler {

    
//定义一个数据源
    public List<string> DataSource
    {
        
get
        {
            List
<string> list = new List<string>()
            {
                
"我爱C#",
                
"我爱.NET",
                
"我爱微软技术"
            };
            
return list;
        }
    }
    
    
public void ProcessRequest (HttpContext context) {
        context.Response.ContentType 
= "text/plain";
    }
 
    
public bool IsReusable {
        
get {
            
return false;
        }
    }

}

 

           (2)搜索数据源返回固定格式数据以字符串形式

             紧接着我们要在ProcessReques方法中加入我们搜索数据源构建返回相应数据集,拼接结果字符串返回给客户端。代码如下:

  public void ProcessRequest (HttpContext context) {
        context.Response.ContentType 
= "text/plain";

        
//接受客户端关键字并且解码
      string searchStr = HttpUtility.UrlDecode(context.Request.QueryString["search"].ToString(), System.Text.Encoding.UTF8);

        
//搜索数据源集合中匹配的关键字
        var result = (from string n in DataSource
                          
where n.Contains(searchStr)
                          select n).ToList
<string>();
        
        StringBuilder sb 
= new StringBuilder(100);
        
//将匹配关键字用符号^ 分割拼接成字符串
        foreach (string str in result as List<string>)
        {
            sb.AppendFormat(
"{0}^", str);
        }
        
//返回客户端
        context.Response.Write(sb.ToString());
    }

      那么我们的基于AJAX的搜索提示功能就顺利的完成了,运行效果如下:

     需要代码的朋友可以留下您的邮箱,我会将代码发送到提供的邮箱中!

作者: 王波洋 发表于 2011-07-31 00:25 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"