需要實現的功能
1:該控件可以從數據庫中讀取數據
2:該控件應該在用戶更改TextBox中內容時使用AJax向服務請求相應數據
3:使用Javascript控制從服務請求到的數據的展現方式
4:使用Javascript注冊相關事件
嗯 基本功能就是這樣了! 那就開始吧!
啟動SQL2008與VS2010後查看了一下可用資源,嗯 還不錯數據庫中有一個包括全國500多個城市的表(表名:Macaco.CityCollection),這張表有三個字段第一個是AutoID 不用說肯定是自動編號列,第二個是EndNumber 嗯這個比較歷害!我也不知道是干什麼的 跳過!第三個字段是City裡面是城市名。
VS2010打開後加載了一下我的Demo工程 首先在Tools類庫項目下添加了一個數據庫表對象屬性模型類,其次添加了一個數據庫表數據訪問類。
代碼如下:
數據表對象屬性模型類
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; }
}
}
數據表數據訪問類
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(自己建的)的文件夾中 然後在裡面
添加如下代碼:
用於響應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),打開後
添加如下代碼:
客戶端功能-前台頁面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 的更多信息,請訪問 <a 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標記 的事件綁定的代碼 呵呵 這次比較多一點 不過基本上每一句都有注釋或提示
詳細代碼如下 :
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
添加如下代碼:
控制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中才可以運行!