JQuery的Autocomplete的选项组合用法

网页下拉框往往需要一些个性化的定制,这个时候用JQuery中的Autocomplete就会出现许多比较复杂的情况,今天这个案例可以说是比较全面地应用到了Autocomplete中的各种参数和选项,值得记录一下。

需求

①页面中有多个并列的input (type=”text”) 控件,控件动态生成,只有类名标识(.txtName)

②这些控件的数据源相同,当其中一个控件选择一项后,其他控件就不能选择相同项

③出现下拉列表后,可以使用鼠标点击、方向键加Enter或Tab键,这3种方式选择,并且选择后,光标移动到文本最左侧

④页面初始化后,可能在一部分文本框有默认值,这取决于数据源

⑤用户输入错误数据时能提示并强制定位到该数据上

以下是代码以及解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
function GetUsers() {
// 初始化后销毁Autocomplete对象
$(".txtName").autocomplete("destroy");
userList = new Array();
userListBak = new Array();
userListInit = new Array();
params = { };
$.wf.post('@Url.Action("GetUserList","EWFS")', params, function (data) {
if (data.isOk) {
// 得到数据
var dd = data.list;
var len = dd.length;
// 将数据装入列表
for (var i = 0; i < len; i++) {
var item = { value: dd[i].Name + "(" + dd[i].OrgName + ")", empNo: dd[i].EmpNo };
// Autocomplete下拉列表的实际数据源
userList.push(item);
// 备份数据源,以便在文本框中的内容变更后将排除了的数据项加回来
userListBak.push(item);
}
var users = $(".txtEmpNo");
var usersCount = users.length;
for (var i = 0; i < usersCount; i++) {
if (users.eq(i).val() != "") {
// 在数据源中排除已经选择的项
SpliceItem(users.eq(i).val());
}
}
// 保存初始化后文本框的默认值列表
for (var i = 0; i < userList.length; i++) {
userListInit.push({ value: userList[i].value, empNo: userList[i].empNo });
}
if (userList != null) {
// 开始Autocomplete方法
$('.txtName').autocomplete({
// 触发本方法的最小输入长度
minLength: 2
// 数据源
, source: userList
// 如果设为true,在菜单显示时,将默认选中第一项
, autoFocus: true
, search: function () {
// 此事件在下拉框将要显示时触发
// 清空隐藏域,以防筛选的时候把该输入框已经输入的项排除在数据源外
$(this).next().val("");
// 查找所有隐藏域的empNo(可以看作empName的Key值)
var existUsers = $(".txtEmpNo");
var usersCount = existUsers.length;
// 从备份数据源获取数据,防止排除某些项的干扰
userList = new Array();
for (var i = 0; i < userListBak.length; i++) {
userList.push({ value: userListBak[i].value, empNo: userListBak[i].empNo });
}
// 将已经输入的项从数据源中排除
for (var i = 0; i < usersCount; i++) {
if (existUsers.eq(i).val() != "") {
SpliceItem(existUsers.eq(i).val());
}
}
// 刷新数据源
$('.txtName').autocomplete({ source: userList });
}
, focus: function (e, ui) {
// 防止在方向键选择选项时把文本框中已经输入的内容覆盖掉
e.preventDefault();
}
, select: function (e, ui) {
// 将选定的empName对应的empNo存入input后面的一个隐藏域中
$(this).next().val(ui.item.empNo);
}
, close: function () {
// 由于IE8及以前版本在Autocomplete选定选项时不会把光标移动到文本左侧,为保持统一的设计,做如下操作
// 此事件在下拉框关闭时触发,注意document.selection只在IE下可以被识别
if (document.selection) {
// 创建选取对象
var rng = document.selection.createRange();
rng.collapse(true);
//将选区的开始和结束都定位在文本框中文本的最左侧,注意负号表示向左移动
rng.moveStart("character", -this.value.length);
rng.moveEnd("character", -this.value.length);
rng.select();
}
}
, change: function (e, ui) {
// 此事件在文本框输入完成(焦点移开),且文本值发生改变的时候触发
// 没有选定选项(但可能手动输入选项,所以需要判断)
if (ui.item == null) {
// 文本框有输入内容
if ($.trim($(this).val()) != "") {
// 验证文本框中的内容是否存在于原始数据源中
var empNo = SpliceItemVerify($.trim($(this).val()));
// 原始数据源中没有输入内容对应的empNo
if (empNo == "") {
// 清空文本框后面的隐藏域
$(this).next().val("");
$.wf.alert("已经存在相关人员,或者无法找到,请重新输入。", function () {
// 输入不完整,强制将光标定位回到此文本框
// 先清空文本框,再Focus,再赋值,这样相当于将文本框的初始状态变为空,以便在此后什么都不输入(但文本框有内容),还能触发此change事件
var temp = $(this).val();
$(this).val("");
$(this).focus();
$(this).val(temp);
// 什么都不输入(但文本框有内容),也能激活下拉列表
$(this).autocomplete("search", temp);
});
} else {
// 重新给隐藏域赋值,确保手动输入时也能获取empNo
$(this).next().val(empNo);
}
}
}
}
}).blur(function () {
// 焦点移开时将空文本框对应的隐藏域清空(不能写在change事件里,因为当文本框的初始状态也为空时,不会触发该事件)
if ($.trim($(this).val()) == "") {
$(this).next().val("");
}
});
}
} else {
$.wf.alert("没有符合条件的人员");
}
}, "json", ".serviceContent");
}

// 将已经输入的数据从数据源中删除
function SpliceItem(empNo) {
for (var i = 0; i < userList.length; i++) {
if (userList[i].empNo == empNo) {
userList.splice(i, 1)
}
}
}

// 根据输入内容查找原始数据源是否存在该值
function SpliceItemVerify(value) {
var empNo = "";
for (var i = 0; i < userListBak.length; i++) {
if ($.trim(userListBak[i].value) == value) {
empNo = userListBak[i].empNo;
}
}
return empNo;
}

需要注意以下两点

①控件的Blur事件和Autocomplete的change事件各有其用处,不能互相代替。Blur在选择下拉框中的内容时就会触发一次,所以对上一个文本框的操作不能在Blur中进行;而change事件只有在文本框焦点移开并且初始内容和最终内容不相同时才能触发,比如当选择了一项然后又删除了,就不会触发该事件
②Autocomplete的事件执行顺序是
create→search→response→open→focus→select→close→change

最后附上Api文档Autocomplete Api