javascript实践之实现仿IE地址栏输入提示
这是一篇阅读《JavaScript高级程序设计》(Professional Javascript for Web Developer)第11章“表单和数据完整性”后的实践。书中所举的例子是实现像Microsoft Outlook之类应用所采用的自动提示文本框。而在我做练习时发现其实现的自动提示比较不完善,于是自己动手对其进行了改进。同时结合了TerryLee的ASP.NET AJAX入门系列(5):使用UpdatePanel控件(二)中的最后一个例子“同一页面上使用多个UpdatePanel”做了这个练习,并将其取名为“javascript实践之实现仿IE地址栏输入提示”。
提示:
- 您可以先翻阅《JavaScript高级程序设计》P313~P315
- 您可以先阅读TerryLee的ASP.NET AJAX入门系列(5):使用UpdatePanel控件(二)
- 开发工具:Microsoft Visual Studio 2005
- 测试浏览器:IE、Mozilla Firefox
- 作为练习之用,实际用途因各人所需
首先新建一个AJAXEnable的空网站,托入一个ScriptManager及两个Update Panel。第一个Panel放置一个文本框、一个列表框(作为提示框)、一个LinkButton(用于提交),及一些指示用的Label;另一个Panel放置一个GridView(用于显示已存在的词)。其中列表框需要放置在一个<div />中以实现显隐。具体编码如下:
1
<form id="form1" runat="server">2
<asp:ScriptManager ID="ScriptManager1" runat="server" />3
<table>4
<tr>5
<td valign="top">6
<asp:UpdatePanel ID="InsertWordUpdatePanel" runat="server" UpdateMode="Conditional">7
<ContentTemplate>8
<table cellpadding="2" style="width:300px; height:100px; border:solid 1px #999999">9
<tr>10
<td style="width: 20px"><asp:Label ID="StrWordLabel" runat="server" AssociatedControlID="StrWordTextBox" Text="Word" /></td>11
<td align="left">12
<input type="text" size="18" id="StrWordTextBox" onkeyup="TextUtil.autosuggest(this, TextUtil.getArrWords(), 'suggestionList')" runat="server" /><br />13
<div id="suggestion" style="width:150px; height:auto; display:none; position:absolute ">14
<select id="suggestionList" size="6" style="width:150px" onclick="setText(this, 'StrWordTextBox')"></select>15
</div>16
</td>17
<td align="center" style="height: 50px">18
<asp:LinkButton ID="InsertButton" runat="server" Text="Insert Word" OnClick="InsertButton_Click" /></td>19
</tr>20
<tr>21
<td colspan="3" align="center" style="height: 23px"><asp:Label ID="InputTimeLabel" runat="server"><%=DateTime.Now %></asp:Label></td>22
</tr>23
</table><br />24
</ContentTemplate>25
</asp:UpdatePanel>26
</td>27
<td valign="top">28
<asp:UpdatePanel ID="WordsUpdatePanel" runat="server" UpdateMode="Conditional">29
<ContentTemplate>30
<asp:GridView ID="WordsGridView" runat="server" AutoGenerateColumns="False" Width="200px">31
<Columns>32
<asp:BoundField DataField="WordID" HeaderText="Word ID" />33
<asp:BoundField DataField="StrWord" HeaderText="Word" />34
</Columns>35
<PagerSettings PageButtonCount="5" />36
</asp:GridView><br />37
<asp:Label runat="server" ID="ListTimeLabel"><%=DateTime.Now %></asp:Label>38
</ContentTemplate>39
<Triggers>40
<asp:AsyncPostBackTrigger ControlID="InsertButton" EventName="Click" />41
</Triggers>42
</asp:UpdatePanel>43
</td>44
</tr>45
</table>46
</form>然后在Default.aspx.cs添加初始GridView的代码,包括Word类与LinkButton的提交功能代码:
1
private List<Word> WordList;2

3
protected void Page_Load(object sender, EventArgs e)4

{5
if (!IsPostBack)6

{7
WordList = new List<Word>();8
WordList.Add(new Word(1, "a"));9
WordList.Add(new Word(2, "aa"));10
WordList.Add(new Word(3, "ab"));11
WordList.Add(new Word(4, "abc"));12
WordList.Add(new Word(5, "abcd"));13
WordList.Add(new Word(6, "eeee"));14

15
ViewState["WordList"] = WordList;16
}17
else WordList = (List<Word>)ViewState["WordList"];18
WordsGridView.DataSource = WordList;19
WordsGridView.DataBind();20
}21

22
[Serializable]23
public class Word24

{25
private int _wordID;26
private string _strword;27

28
public int WordID29

{30

get
{ return _wordID;}31
}32

33
public string StrWord 34

{35

get
{ return _strword;}36
}37

38
public Word(int wordID, string strword) 39

{40
_wordID = wordID;41
_strword = strword;42
}43
}44

45
protected void InsertButton_Click(object sender, EventArgs e)46

{47

48

if (String.IsNullOrEmpty(StrWordTextBox.Value))
{ return; }49

50
int wordID = WordList[WordList.Count - 1].WordID + 1;51

52
string strWord = Server.HtmlEncode(StrWordTextBox.Value);53

54
StrWordTextBox.Value = String.Empty;55

56
WordList.Add(new Word(wordID, strWord));57
ViewState[" WordList"] = WordList;58

59
WordsGridView.DataBind();60
WordsGridView.PageIndex = WordsGridView.PageCount;61

62
}接着搬出书中所举的例子的部分JS代码:
1
var ListUtil = new Object();2
3

ListUtil.add = function (oListbox, sName, sValue)
{4
var oOption = document.createElement("option");5
oOption.appendChild(document.createTextNode(sName));6

if (arguments.length == 3)
{7
oOption.setAttribute("value", sValue);8
}9
oListbox.appendChild(oOption);10
};11
12

ListUtil.remove = function (oListbox, iIndex)
{13
oListbox.remove(iIndex);14
};15
16

ListUtil.clear = function (oListbox)
{17

for (var i=oListbox.options.length-1; i>=0; i--)
{18
ListUtil.remove(oListbox, i);19
}20
};其中的ListUtil是用于放置各个方法的简单的对象,具体涉及到的知识请参阅《JavaScript高级程序设计》。
以下将详细讲述一下自动提示的实现方法与其相关的代码:
一、匹配
第一步是写一个方法来搜索字符串数组并返回以特定字符开头的所有值(例如传入a,那么这个方法要返回数组中所有以字母a开头的字符串)。这个方法称为TextUtil.autosuggestMatch(),它需要两个参数:要匹配的文本及要进行匹配的单词数组。这里根据要增强的功能对此方法进行了改写:
1
var TextUtil = new Object(); //容器对象
2
3
TextUtil.autosuggestMatch = function (sText, arrValues)
{
4
var arrResult = new Array;
5
var arrChar = new Array; //用于存放Text分解出的单个字符的数组
6
if (sText != "")
{
7
arrChar = sText.split(""); //分解Text并存入数组
8
var cChar = arrChar[arrChar.length-1];
9
var iCharLength = arrChar.length;
10
var iArrValuesLength = arrValues.length
11
for (var i=0; i<iArrValuesLength; i++)
{
12
if (arrValues[i].indexOf(cChar) == iCharLength-1) //判断单词中对应的索引位置上的字符是否与新输入的字符一样
13
arrResult.push(arrValues[i]);
14
}
15
}
16
return arrResult;
17
};
var TextUtil = new Object(); //容器对象2
3

TextUtil.autosuggestMatch = function (sText, arrValues)
{4
var arrResult = new Array;5
var arrChar = new Array; //用于存放Text分解出的单个字符的数组6

if (sText != "")
{7
arrChar = sText.split(""); //分解Text并存入数组8
var cChar = arrChar[arrChar.length-1];9
var iCharLength = arrChar.length;10
var iArrValuesLength = arrValues.length11

for (var i=0; i<iArrValuesLength; i++)
{12
if (arrValues[i].indexOf(cChar) == iCharLength-1) //判断单词中对应的索引位置上的字符是否与新输入的字符一样13
arrResult.push(arrValues[i]);14
}15
}16
return arrResult;17
};方法中,同样是先设定一个方法的简单容器对象TextUtil,然后通过判断单词中对应索引位置上的字符是否与新输入的字符一样来从选定的单词数组中挑选出可做为推荐的单词。
书中实现的是凡含有该字符的单词都会被挑选,而不管是否对应,且接下来的字符判断不依赖第一个字符筛选的结果(如输入a得2a、a3、ba、ab,而当继续输入b形成ab时,得到的是ab和ba,而不是ab),这不是我们想看到的。所以在接下去的方法中也进行了更改。

TextUtil.autosuggestMatch = function (sText, arrValues)
{
var arrResult = new Array;

if (sText != "")
{
for (var i=0; i < arrValues.length; i++)
{
if (arrValues[i].indexOf(sText) == 0)
{
arrResult.push(arrValues[i]);
}
}
}
return arrResult;
};二、匹配机制
完成匹配方法后,要创建脚本TextUtil.autoSuggest()方法。
1
TextUtil.autosuggest = function (oTextbox, arrValues,sListboxId)
{
2
var oDiv = document.getElementById("suggestion");
3
oDiv.style.display = "block";
4
var oListbox = document.getElementById(sListboxId);
5
6
if (oTextbox.value.split("").length > 1)
{ //当输入的字符前已输入过字符时备选的单词数组为前一个字符输入后所得的推荐
7
arrValues = TextUtil.getSuggestionListWords();
8
}
9
ListUtil.clear(oListbox);
10
var arrMatches = TextUtil.autosuggestMatch(oTextbox.value, arrValues);
11
for (var i=0; i<arrMatches.length; i++)
{
12
ListUtil.add(oListbox, arrMatches[i]);
13
}
14
};

TextUtil.autosuggest = function (oTextbox, arrValues,sListboxId)
{ 2
var oDiv = document.getElementById("suggestion");3
oDiv.style.display = "block";4
var oListbox = document.getElementById(sListboxId);5
6

if (oTextbox.value.split("").length > 1)
{ //当输入的字符前已输入过字符时备选的单词数组为前一个字符输入后所得的推荐7
arrValues = TextUtil.getSuggestionListWords();8
} 9
ListUtil.clear(oListbox);10
var arrMatches = TextUtil.autosuggestMatch(oTextbox.value, arrValues);11

for (var i=0; i<arrMatches.length; i++)
{12
ListUtil.add(oListbox, arrMatches[i]);13
}14
};其中最关键的地方是判断文本框中的字符数,当大于1时,即当输入字符前已经输入过字符时,备选的单词数组为前一个字符输入后所得的推荐。这样便解决了前头所提到的不足。
其中文本框中输入第一个字符后所得的推荐是从DridView中获取,方法如下:
1
TextUtil.getArrWords = function ()
{
2
var arrWords = new Array;
3
var WordsGridView = document.getElementById("WordsGridView");
4
//alert(WordsGridView);
5
for (var i=1; i<WordsGridView.childNodes[0].childNodes.length; i++)
{
6
arrWords.push(WordsGridView.childNodes[0].childNodes[i].lastChild.firstChild.nodeValue);
7
}
8
arrWords.sort();
9
return arrWords;
10
}

TextUtil.getArrWords = function ()
{2
var arrWords = new Array;3
var WordsGridView = document.getElementById("WordsGridView");4
//alert(WordsGridView);5

for (var i=1; i<WordsGridView.childNodes[0].childNodes.length; i++)
{6
arrWords.push(WordsGridView.childNodes[0].childNodes[i].lastChild.firstChild.nodeValue);7
}8
arrWords.sort();9
return arrWords;10
}其中涉及到的获取前一个字符输入后所得的推荐的方法代码如下:
1
TextUtil.getSuggestionListWords = function ()
{
2
var arrSuggestionListWords = new Array;
3
var suggestionList = document.getElementById("suggestionList");
4
5
for (var i=0; i<suggestionList.options.length; i++)
{
6
arrSuggestionListWords.push(suggestionList.options[i].text);
7
}
8
arrSuggestionListWords.sort();
9
//alert(arrSuggestionListWords.length);
10
return arrSuggestionListWords;

TextUtil.getSuggestionListWords = function ()
{2
var arrSuggestionListWords = new Array;3
var suggestionList = document.getElementById("suggestionList");4

5

for (var i=0; i<suggestionList.options.length; i++)
{6
arrSuggestionListWords.push(suggestionList.options[i].text);7
}8
arrSuggestionListWords.sort();9
//alert(arrSuggestionListWords.length);10
return arrSuggestionListWords;单击推荐中的某一项,把其推送到文本框的方法较为简单:
1
function setText(oListbox, sTextboxId)
{
2
var oTextbox = document.getElementById(sTextboxId);
3
if (oListbox.selectedIndex > -1)
{
4
oTextbox.value = oListbox.options[oListbox.selectedIndex].text;
5
}
6
}

function setText(oListbox, sTextboxId)
{2
var oTextbox = document.getElementById(sTextboxId);3

if (oListbox.selectedIndex > -1)
{4
oTextbox.value = oListbox.options[oListbox.selectedIndex].text;5
}6
}效果:

注:
- 本例所提供的自动完成功能是区分大小写的
- 在这个基础上我们还可以添加文本框失去焦点或者退格键事件等来扩充其功能
- 才疏学浅,请多赐教
该篇到此结束,谢谢阅读!
