前段時間,寫一個用戶部門的管理頁面,需要對后臺獲取的用戶數(shù)據(jù)實現(xiàn)英漢檢索功能。
![](/d/20211017/2e65119568893907db18e28d912620eb.gif)
同時,選定一個選項之后,需要觸發(fā)事件與后臺交互,將該用戶所在的部門顯示到頁面右邊的ListBox控件中。
![](/d/20211017/82ad0c3f05c8fcf686916cf1afddd494.gif)
![](/d/20211017/10714872e6ca68730baf136e7b345da5.gif)
一、Dojo的FilteringSelect組件實現(xiàn)拼音檢索功能
在網(wǎng)上有不少相關(guān)的介紹,其中比較經(jīng)典的有"海盜亂語"的關(guān)于重寫Dojo的FilteringSelect組件實現(xiàn)拼音檢索功能的介紹(地址http://cosbor.web-144.com/?p=38、http://cosbor.web-144.com/?p=52)。由于作者的Demo后臺以及pinyin4j的jar包都是基于Java平臺的,本人花了一點時間將其實現(xiàn)在.Net平臺下,并成功的實現(xiàn)了FilteringSelect選中事件的注冊。實現(xiàn)原理請詳細(xì)參考"海盜亂語"博客中的分析,這里對.Net平臺下的實現(xiàn)思路做簡要說明,并貼出源碼供大家參考(在此對作者提供的思路表示感謝!):
首先,引入Dojo工具包,在dojo目錄下添加一個"test"文件夾,新建一個FilteringSelect.js文件,如下圖:
![](/d/20211017/aebc187cf491140fbaa743a4d2886e52.gif)
FilteringSelect.js文件的作用是重寫FilteringSelect組件,"海盜亂語"的博文中給出了的代碼清單,為方便起見轉(zhuǎn)貼如下:
復(fù)制代碼 代碼如下:
define([
"dojo/_base/declare", // declare,
"dojo/dom-attr", // domAttr.get
"dijit/form/FilteringSelect"
], function(declare, domAttr ,FilteringSelect){
return declare("test.FilteringSelect", [FilteringSelect], {
displayValueAttr:null, //新增一個自定義屬性,用于指定FilteringSelect的textbox中最終顯示內(nèi)容的屬性字段
// summary:
// 覆蓋dijit.form._AutoCompleterMixin的同名方法,使FilteringSelect支持displayValueAttr指定textbox最終顯示內(nèi)容,而不是默認(rèn)顯示searchAttr指定的字段內(nèi)容
_announceOption: function(/*Node*/ node){
if(!node){
return;
}
// pull the text value from the item attached to the DOM node
var newValue;
if(node == this.dropDown.nextButton ||
node == this.dropDown.previousButton){
newValue = node.innerHTML;
this.item = undefined;
this.value = '';
}else{
var item = this.dropDown.items[node.getAttribute("item")];
var displayAttr = this.displayValueAttr!=null?this.displayValueAttr:this.searchAttr;//此處判斷是否配置了自定義屬性displayValueAttr
newValue = (this.store._oldAPI ? // remove getValue() for 2.0 (old dojo.data API)
this.store.getValue(item, displayAttr) : item[displayAttr]).toString();//將this.searchAttr替換為displayAttr
this.set('item', item, false, newValue);
}
// get the text that the user manually entered (cut off autocompleted text)
this.focusNode.value = this.focusNode.value.substring(0, this._lastInput.length);
// set up ARIA activedescendant
this.focusNode.setAttribute("aria-activedescendant", domAttr.get(node, "id"));
// autocomplete the rest of the option to announce change
this._autoCompleteText(newValue);
},
});
});
然后,新建一個WebForm頁面,放置一個FilteringSelect控件,數(shù)據(jù)源取值為頁面類繼承過來的userListstr字段,頁面前臺代碼如下:
復(fù)制代碼 代碼如下:
%@ Page Title="" Language="C#" AutoEventWireup="true" CodeFile="OrgRelation.aspx.cs" Inherits="OrgRelation" %>
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
html xmlns="http://www.w3.org/1999/xhtml">
head id="Head1" runat="server">
title>/title>
script src="Scripts/jquery-1.4.1-vsdoc.js" type="text/javascript">/script>
link href="Scripts/dojo/dijit/themes/claro/claro.css" rel="stylesheet" type="text/css" />
link href="Scripts/dojo/dojo/resources/dojo.css" rel="stylesheet" type="text/css" />
script src="Scripts/dojo/dojo/dojo.js" type="text/javascript">/script>
script type="text/javascript">
//參數(shù)設(shè)置
require([
'test/FilteringSelect',
'dojo/store/Memory',
'dojo/domReady!'
], function (FilteringSelect, Memory) {
var jsonstr = '%=userListStr%>';
var json = jQuery.parseJSON(jsonstr);
var obj = {data:""};
obj['data'] = json;
var selectStore = new Memory(obj);
//創(chuàng)建FilteringSelect
var testSelect = new FilteringSelect({
id: "testSelect",
name: "test",
value: "",
store: selectStore,
searchAttr: 'py', //指定輸入文本框進(jìn)行用來進(jìn)行檢索的字段
labelAttr: 'name', //指定下拉菜單中顯示的字段
displayValueAttr: 'name', //指定選中下拉菜單后顯示在輸入框中的字段
required: false,
autoComplete: false
}, "testSelect");
});
//注冊失去焦點事件
window.onload = function () {
function selblur() {
var guid = dijit.byId('testSelect').attr('value');
alert(guid);
window.location.href = "OrgRelation.aspx?userId=" + guid;
return false;
}
var sel = dojo.byId("testSelect");
dojo.connect(sel, "onblur", selblur);
};
/script>
/head>
body>
form id="Form1" method="post" runat="server">
div align="center" id="title">
strong>編輯用戶部門關(guān)系/strong>
/div>
div style="text-align: center;width: 100%;padding-top: 100px;font-size:15px;">選擇用戶:input id="testSelect"/>
/div>
/form>
/body>
/html>
最后,在頁面加載事件中獲取用戶數(shù)據(jù),序列化之后,賦給protected類型的userListstr字段。其中這里引用到微軟提供的獲取漢字拼音的類庫ChnCharInfo.dll,代碼請單如下:
復(fù)制代碼 代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.International.Converters.PinYinConverter;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Script.Serialization;
public partial class OrgRelation : System.Web.UI.Page
{
protected string userListStr = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GetUsers();
}
}
//與前臺頁面Json對象格式對應(yīng)的類
public class UserInfo
{
public string name { get; set; }
public string id { get; set; }
public string py { get; set; }
}
protected void GetUsers()
{
//獲取用戶信息,及每項記錄的拼音簡碼
ListUser> list =new BLL.User().GetUsers();
ListUserInfo> UserInfoList = new ListUserInfo>();
foreach (User item in list)
{
UserInfo userInfo= new UserInfo();
userInfo.id = item.UserId;
userInfo.name = item.User Name;
userInfo.py = GetPY(item.UserName);
UserInfoList .Add(userInfo);
}
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
//執(zhí)行序列化 并賦值
userListStr = jsonSerializer.Serialize(UserInfoList);
}
#region 拼音檢索的相關(guān)方法
/// summary>
/// 獲得一個漢字字符的拼音的字符串集合,并處理聲調(diào)和空值
/// /summary>
/// param name="ch">漢字字符/param>
/// returns>/returns>
public static Liststring> GetPinyins(char ch)
{
Liststring> list = new Liststring>();
ChineseChar cc = new ChineseChar(ch); //獲得包含漢字信息的對象
foreach (string item in cc.Pinyins)
{
if (item != null)
{
string temp = item.Substring(0, item.Length - 1);
if (!list.Contains(temp))
{
list.Add(temp);
}
}
}
return list;
}
/// summary>
/// 得到一個詞組的拼音的首字母字符串(多音取第一個)
/// /summary>
/// returns>/returns>
public static string GetPY(string str)
{
Regex reg = new Regex(@"[\u4e00-\u9fa5]");
StringBuilder sb = new StringBuilder();
for (int i = 0; i str.Length; i++)
{
string ch = str[i].ToString();
if (reg.IsMatch(ch))
{
string s = GetPinyins(str[i])[0];
sb.Append(s[0]);
}
else
{
sb.Append(ch);
}
}
return sb.ToString();
}
#endregion
}
這樣拼音檢索的功能就完成了。不過有兩點不盡人意的地方:1.使用拼音檢索后,不好再使用中文檢索,2.網(wǎng)上查了很久,沒有選中項改變事件介紹,代碼中只是注冊了一個失去焦點事件,在與后臺交互方面不太方便(可能是本人對dojo事件不熟,歡迎對dojo api有研究的大俠指點)。
二、JqueryUI的autocomplete插件實現(xiàn)拼音檢索功能
其實JqueryUI也提供了一個非常好用的插件--autocomplete,它與ChnCharInfo.dll類庫配合使用,不僅能實現(xiàn)同樣優(yōu)秀的檢索功能,而且能夠很好的解決上述兩個問題。不妨來看看:
需要用到的相關(guān)組件和引用的類庫:Jquery-UI 、漢字拼音轉(zhuǎn)換語言包類庫ChnCharInfo .dll和Json對象序列化類庫Newtonsoft.Json.dll,如下所示:
![](/d/20211017/86b1a6c410dda49bc9850768910729a7.gif)
1.WebForm的aspx頁面實現(xiàn):
首先引入jquery-1.8.2.js、jquery-ui-1.9.0.custom.js、jquery-ui-1.9.0.custom.css,然后在頁面加載完成的事件中寫如下腳本:
復(fù)制代碼 代碼如下:
script type="text/javascript">
$(function () {
$("#selCompate").autocomplete({
source: "GetUser.ashx",
minLength: 1,
//以下為選中事件
select: function (event, ui) {
temp = ui.item;
$("#hidcontactid").val(temp.id);
$("#hidcontactname").val(temp.label);
$("#form2").attr("action", "./OrgRelation.aspx?contactId=" + temp.id + "contactName=" + temp.label);
$("#form2").submit();
}
});
$("#selCompate").val($("#hidcontactname").val())
});
/script>
其中第4行的 source: "GetUser.ashx",是指鍵入字符后,發(fā)送異步請求的地址,GetUser.ashx負(fù)責(zé)向請求的客戶端提供滿足Json格式的用戶信息;第5行的minLength: 是輸入到幾個字符時開始發(fā)送異步請求;第7行的select: function(event, ui){}即選中事件,ui.item表示被選中的項;第8-9行的隱藏域存值,是為了頁面刷新后能重新獲取該選中項的相關(guān)信息,重新寫回頁面以備用;第10-11行以當(dāng)前選中項的id和label被為參數(shù)向OrgRelation.aspx發(fā)送post請求,是實現(xiàn)將選中用戶的所在部門查詢處來,顯示到頁面右側(cè)的ListBox控件中,其服務(wù)端實現(xiàn)與本次討論的內(nèi)容無關(guān),代碼就不貼出來了。
頁面的完整代碼清單如下:
復(fù)制代碼 代碼如下:
%@ Page Title="" Language="C#" AutoEventWireup="true" CodeFile="OrgRelation.aspx.cs"
Inherits="OrgRelation"%>
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
html xmlns="http://www.w3.org/1999/xhtml">
head id="Head1" runat="server">
title>/title>
script src="Scripts/jquery-1.8.2.js" type="text/javascript">/script>
script src="Scripts/jquery-ui-1.9.0.custom.js" type="text/javascript">/script>
link href="css/ui-lightness/jquery-ui-1.9.0.custom.css" rel="stylesheet" type="text/css" />
script type="text/javascript">
$(function () {
$("#selCompate").autocomplete({
source: "GetUser.ashx",
minLength: 1,
//以下為選中事件
select: function (event, ui) {
temp = ui.item;
$("#hidUserId").val(temp.id);
$("#hidUserName").val(temp.label);
$("#form2").attr("action", "./OrgRelation.aspx?UserId=" + temp.id + "UserName=" + temp.label);
$("#form2").submit();
}
});
$("#selCompate").val($("#hidUserName").val())
});
/script>
/head>
body>
form id="form2" method="post" action="./OrgRelation.aspx" name="sendForm">/form>
form id="Form1" method="post" runat="server" >
input type="hidden" id="hidUserId" name="hidUserId" value="%=currentUserId%>" />
input type="hidden" id="hidUserName" name="hidUserName" value="%=currentUserName%>"/>
asp:ScriptManager ID="ScriptManager1" runat="server">
/asp:ScriptManager>
div id="outline">
div align="center" id="title">
strong>編輯用戶部門關(guān)系/strong>
/div>
div id="main">
table align="center">
tr>
td>
div>
b>選擇用戶:/b>nbsp;
asp:UpdatePanel ID="UpdatePanel2" runat="server">
ContentTemplate>
input type="text" id="selCompate" style="line-height: 10px; margin-top: 0px;
margin-left: 0px; height: 23px;"
runat="server" />
/ContentTemplate>
/asp:UpdatePanel>br />
b>選擇部門:/b>
/div>
br />
/td>
td>
/td>
td>
/td>
/tr>
tr>
td valign="top" width="41%">
div id="left">
asp:UpdatePanel ID="UpdatePanel1" runat="server">
ContentTemplate>
asp:TreeView ID="TreeViewOrgData" runat="server" Font-Names="微軟雅黑" Height="385px"
Font-Size="11pt" ForeColor="Black" BackColor="AliceBlue" OnTreeNodeCollapsed="TreeViewOrgData_TreeNodeCollapsed"
OnTreeNodeExpanded="TreeViewOrgData_TreeNodeExpanded" ShowCheckBoxes="All">
/asp:TreeView>
/ContentTemplate>
/asp:UpdatePanel>
/div>
/td>
td align="center" valign="middle" width="18%">
p>
asp:Button ID="btnAddOrg" runat="server" Width="85px" Text="添加部門 >>" Height="22px"
BorderStyle="Solid" BorderColor="DarkGray" BackColor="GhostWhite" Font-Size="9pt"
OnClick="btnAddOrg_Click">/asp:Button>/p>
p>
asp:Button ID="btnRemoveOrg" runat="server" Width="85px" Text=" 移除部門" Height="22px"
BorderStyle="Solid" BorderColor="DarkGray" BackColor="GhostWhite" Font-Size="9pt"
OnClick="btnRemoveOrg_Click">/asp:Button>/p>
/td>
td valign="top" align="center" width="41%">
div id="right">
asp:ListBox ID="LBOrg" runat="server" Width="300px" Height="350px" Rows="13" BackColor="AliceBlue"
Font-Size="11pt" SelectionMode="Multiple" >
/asp:ListBox>
/div>
/td>
/tr>
/table>
/div>
br />
div align="center" id="bottom">
asp:Button ID="btnBack" runat="server" Text="·返 回·" BackColor="#f8f8ff" />nbsp;nbsp;
asp:Button ID="btnSave" runat="server" Text="·保 存·" BackColor="#f8f8ff"
onclick="btnSave_Click" />
/div>
/div>
/form>
/body>
/html>
2.Global.asax中用戶數(shù)據(jù)的準(zhǔn)備
由于這里的用戶數(shù)據(jù)不經(jīng)常變化,考慮到搜索是需要頻繁的向服務(wù)端請求數(shù)據(jù),因此將用戶數(shù)據(jù)存入了Application中,這樣搜索時直接從Application中取,不用每次去數(shù)據(jù)庫查詢。
Application對象的賦值是在全局應(yīng)用程序Global.asax的 Application_Start事件中完成的,代碼如下:
復(fù)制代碼 代碼如下:
void Application_Start(object sender, EventArgs e)
{
Application.Lock();
Application["User"] = GetUsers();
Application.UnLock();
}
獲取用戶信息的GetUser方法中,同時完成了拼音簡碼的獲取,代碼如下:
復(fù)制代碼 代碼如下:
protected Liststring> GetUsers()
{
ListModel.User> list = new BLL.User().GetUsers();
Liststring> UserList = new Liststring>();
foreach (Model.User item in list)
{
UserList .Add(item.Id+"|"+item.Name+"|"+GetPY(item.Name).Replace(" ","").ToLower());
}
return UserList ;
}
/// summary>
/// 獲得一個漢字字符的拼音的字符串集合,并處理聲調(diào)和空值
/// /summary>
/// param name="ch">漢字字符/param>
/// returns>/returns>
public static Liststring> GetPinyins(char ch)
{
Liststring> list = new Liststring>();
Microsoft.International.Converters.PinYinConverter.ChineseChar cc = new Microsoft.International.Converters.PinYinConverter.ChineseChar(ch); //獲得包含漢字信息的對象
foreach (string item in cc.Pinyins)
{
if (item != null)
{
string temp = item.Substring(0, item.Length - 1);
if (!list.Contains(temp))
{
list.Add(temp);
}
}
}
return list;
}
/// summary>
/// 得到一個詞組的拼音的首字母字符串(多音取第一個)
/// /summary>
/// returns>/returns>
public static string GetPY(string str)
{
Regex reg = new Regex(@"[\u4e00-\u9fa5]");
StringBuilder sb = new StringBuilder();
for (int i = 0; i str.Length; i++)
{
string ch = str[i].ToString();
if (string.IsNullOrEmpty(ch))
{
}
else if (reg.IsMatch(ch))
{
string s = GetPinyins(str[i])[0];
sb.Append(s[0]);
}
else
{
sb.Append(ch);
}
}
return sb.ToString();
}
至于Application與數(shù)據(jù)庫中數(shù)據(jù)的一致的考慮,可提供一個一般處理程序UpdateApplication.ashx負(fù)責(zé)更新Application(代碼與Global.asax中基本相同),當(dāng)數(shù)據(jù)庫發(fā)生變化時,訪問UpdateApplication.ashx即可更新Application["Contact"]對象。
3.GetUser.ashx中返回符合檢索條件的數(shù)據(jù)
GetUser.ashx中響應(yīng)搜索事件的服務(wù)端代碼清單如下:
復(fù)制代碼 代碼如下:
%@ WebHandler Language="C#" Class="GetUser" %>
using System;
using System.Web;
using BLL;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web.Script.Serialization;
using Microsoft.International.Converters.PinYinConverter;
public class GetUser :JavaScriptSerializer,IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
int i = 0;
Liststring> strlist = context.Application["User"] as Liststring>;
string inputStr = context.Request.QueryString.Get("term").ToLower();
ListUserItem> userList = new ListUserItem>();
foreach (string str in strlist)
{
string[] userArr = str.Split('|');
if (i 10)
{
Regex reg = new Regex(@"^" + inputStr);
if (reg.IsMatch(userArr[2]) || reg.IsMatch(userArr[1]))
{
UserItem item = new UserItem();
item.id = userArr[0];
item.label = userArr[1];
item.value = userArr[2];
userList.Add(item);
i++;
}
}
else
{
break;
}
}
context.Response.ContentType = "application/json";
string output = Newtonsoft.Json.JsonConvert.SerializeObject(userList);
context.Response.Write(output);
}
public bool IsReusable
{
get
{
return false;
}
}
}
public class UserItem
{
public string id { get; set; }
public string label { get; set; }
public string value { get; set; }
}
第17行是獲取文本框中輸入的檢索字符串inputstr,這里使用正則表達(dá)式對獲取名稱以inputstr開頭的記錄(中文檢索)或者拼音簡碼以inputstr開頭的記錄(拼音檢索)。如果需要模糊檢索功能,可以修改第25行的正則表達(dá)式為:Regex reg = new Regex(inputStr);即可。如果需要更多字段的復(fù)合檢索(例如用戶手機號,郵箱地址等),也只要Application對像賦值時獲取相關(guān)的字段信息,在26行的if判斷中增加相應(yīng)匹配項即可。
其中UserItem是為頁面提供Json對象的類,label是必須字段,搜索框中顯示的內(nèi)容即該字段的值。得到符合條件的數(shù)據(jù)集合后,需要使用Newtonsoft.Json.JsonConvert的SerializeObject方法進(jìn)行序列化,再返回給客戶端。
到此,即實現(xiàn)了本文開篇的貼圖效果。