在用下拉列表的时候,如果数据过多用默认html <select/>来完成,用
户使用时候会很难迅速的选择到想要的选项,所以AutoComplete 控件应
运而生……
下面是我利用Jquery 插件功能开发的AutoComplete控件
(function($) {
$.fn.extend({
createCombo : function(config) {
config = config || {};
var defaults = {
mode:"local",
store:{},
method:"get",
edit:true,
//每行最大高度,如果超过最大高度会有滚动条
listMaxHeight: 200,
//每行的高度
listItemHeight: 20,
//调整列表的宽度
listWidthOffset:0,
//if true, the value of selectbox will be
propagated to the combobox
triggerSelected: true,
selectOnFocus:true,
//icon 路径
blankImageSrc: "images/s.gif",
hiddenId:"___"+$(this).attr('id'),
hiddenName:"___"+$(this).attr('name'),
emptyText:"--Select--",
//未选中下拉列的颜色
unselectedLiColor: "rgb(255, 255, 255)",
//选中的下拉列的颜色
selectedLiColor: "rgb(223, 232, 246)",
onChanged:function(){},
comboCss:"combo"
};
config = $.extend(defaults,config);
var autocomplete = function(obj)
{
var _index = 0;
return obj.each(function() {
var $selectbox = $(this);
if(config.store.length==1){
if(typeof config.emptyValueText!
='undefined'){
$selectbox.prepend("<option
value=''>"+config.emptyValueText+"</option>");
}
$selectbox.append("<option
value="+config.store.value+">"+config.store.name
+"</option>");
}else{
if(typeof config.emptyValueText!
='undefined'){
$selectbox.prepend("<option
value=''>"+config.emptyValueText+"</option>");
}
for(var
i=0;i<config.store.length;i++)
{
$selectbox.append("<option
value="+config.store[i].value+">"+config.store[i].name
+"</option>");
}
}
var $wrapper = $selectbox.wrap
("<div>").hide().parent().addClass(config.comboCss);
var $textInput = $("<input />").appendTo
($wrapper).attr("autocomplete","off").attr("size", "20");
var _style = "";
if(!config.edit){
_style+="cursor: pointer;";
$textInput.attr('readonly','true');
$textInput.click(function()
{$icon.click()});
}
if(typeof config.width=='string')
{
_style+="width:"+config.width+";";
}
if(typeof config.height=='string')
{
_style+="height:"+config.height+";";
}
if(typeof config.style){
_style+=config.style;
}
if(""!=config.emptyText)
{
//$selectbox.prepend("<option
value=''>"+config.emptyText+"</option>");
//$selectbox.get(0).selectedIndex=0;
$textInput.attr("value",
config.emptyText);
}else
{
$textInput.attr("value","");
}
$textInput.attr("style",_style);
if(typeof config.textCss!='undefined'){
$textInput.attr
("class",config.textCss);
}
var $icon = $("<img />").appendTo
($wrapper).attr("src", config.blankImageSrc);
/*
if($selectbox.attr('id')!=""){
if($selectbox.attr('name')!=""){
var $hiddenInput =
$("<input/>").appendTo($wrapper).attr
("id",config.hiddenId).attr("name",config.hiddenName).hide();
}
else
{
var $hiddenInput =
$("<input/>").appendTo($wrapper).attr
("id",config.hiddenId).attr("name",config.hiddenName
+_index).hide();
}
}
else{
if($selectbox.attr('name')!="")
{
var $hiddenInput =
$("<input/>").appendTo($wrapper).attr("id",config.hiddenId
+_index).attr("name",config.hiddenName).hide();
}
else
{
var $hiddenInput =
$("<input/>").appendTo($wrapper).attr("id",config.hiddenId
+_index).attr("name",config.hiddenName+_index).hide();
}
}
*/
_index++;
if(typeof config.listWidthOffset!
="number"){
alert("listWidthOffset must be
number");
}
var $list = $("<ul />").appendTo
($wrapper).css({display: "none",width:$textInput.width
()+config.listWidthOffset+"px", maxHeight:
config.listMaxHeight});
$selectbox.children().each(function() {
$("<li />").appendTo($list).text
($(this).text()).css({display: "block",width:
$textInput.width()+"px", height: config.listItemHeight});
});
var $listItems = $list.children();
if (config.triggerSelected) {
var val = $selectbox.attr("value");
$selectbox.children().each(function()
{
var $this = $(this);
if ($this.attr("selected") == true) {
$textInput.attr("value",
$this.text());
//$hiddenInput.attr("value",
$this.text());
}
});
}
var sync = function() {
var curVal = $.trim($textInput.attr
("value"));
$selectbox.children().each(function()
{
var $this = $(this);
if ($this.text() == curVal) {
$selectbox.attr("value",
$this.attr("value"));
config.onChanged($this.attr
("value"),$this.text());
if(config.selectOnFocus)
{
$textInput.focus();
}
$selectbox.trigger("change");
}
});
};
var getNumHidden = function() {
var numHidden = 0;
$listItems.each(function() {
if ("none" == this.style.display) {
++numHidden;
}
});
return numHidden;
};
var correctListHeight = function() {
var css = {};
css.height = ($listItems.get().length -
getNumHidden()) * config.listItemHeight;
if (css.height > config.listMaxHeight) {
css.overflowY = "scroll";
}
else {
css.overflowY = "hidden";
}
$list.css(css);
};
correctListHeight();
$icon.bind("click", function() {
if ("block" == $list.get()
[0].style.display) {
$list.css({display: "none"});
}
else {
$list.css({display: "block"});
selectFirst();
}
});
var liClick = function() {
$textInput.attr("value", $(this).text());
sync();
filterList();
$list.css({display: "none"});
};
$listItems.bind("click", liClick);
var filterList = function() {
if(config.edit){
var currentVal = $textInput.attr
("value");
if (currentVal) {
currentVal =
currentVal.toLowerCase();
}
$listItems.each(function() {
var $this = $(this);
if ($this.text().toLowerCase
().search(currentVal) != 0) {
$this.css({display:
"none"});
}
else {
$this.css({display:
"block"});
}
});
correctListHeight();
}
};
$textInput.bind("keyup", function(e) {
if ((13 == e.keyCode) || (40 ==
e.keyCode) || (38 == e.keyCode)) {
return;
}
sync();
filterList();
if (getNumHidden() < $listItems.get
().length) {
$list.css({display: "block"});
selectFirst();
}
else {
$list.css({display: "none"});
}
});
//just highlights list items
$listItems.bind("mouseover", function() {
$listItems.css({backgroundColor:
config.unselectedLiColor});
$(this).css({backgroundColor:
config.selectedLiColor});
});
//selects first item in the dropdown list
var selectFirst = function() {
try {
$listItems.each(function() {
if ("block" ==
this.style.display) {
$(this).trigger("mouseover");
// throw new Exception();
}
});
} catch (e) {}
};
//returns the selected item in the dropdown
list, or null
var getSelected = function() {
var listItems = $listItems.get();
for (var i = 0, len = listItems.length; i
< len; ++i) {
if (config.selectedLiColor ==
listItems[i].style.backgroundColor) {
return $(listItems[i]);
}
}
return null;
};
$(document).bind("click", function(e) {
if (($list.get()[0] == e.target) ||
($textInput.get()[0] == e.target) || ($icon.get()[0] ==
e.target)) {
$textInput.get()[0].focus();
return;
}
$list.css({display: "none"});
});
var correctScroll = function() {
var scrollNeed = 0;
try {
$listItems.each(function() {
var $this = $(this);
if (config.selectedLiColor ==
this.style.backgroundColor) {
scrollNeed += parseInt
($this.height());
throw new Exception();
}
scrollNeed += parseInt
($this.height());
});
} catch (e) {}
var list = $list.get()[0];
scrollNeed -= config.listMaxHeight;
if (list.scrollTop < scrollNeed) {
list.scrollTop += scrollNeed -
list.scrollTop;
}
};
//selects dropdown list's item next to the
currecntly selected. For keyboard navigation
var selectNext = function() {
var $selected = getSelected();
if (!$selected) {
return;
}
var $next = $selected.next();
while ($next.get().length) {
if ("block" == $next.get()
[0].style.display) {
$listItems.css({backgroundColor:
config.unselectedLiColor});
$next.css({backgroundColor:
config.selectedLiColor});
correctScroll();
return;
}
$next = $next.next();
}
};
//select previous dropdown list's item
to the currecntly selected. For keyboard navigation
var selectPrev = function() {
var $selected = getSelected();
if (!$selected) {
return;
}
var $prev = $selected.prev();
while ($prev.get().length) {
if ("block" == $prev.get()
[0].style.display) {
$prev.trigger("mouseover");
var scrollNeed = 0;
try {
$listItems.each(function() {
scrollNeed += $(this).height
();
if (config.selectedLiColor ==
this.style.backgroundColor) {
scrollNeed -= $(this).height
();
throw new Exception();
}
});
} catch (e) {}
var list = $list.get()[0];
if (list.scrollTop >= scrollNeed) {
list.scrollTop -= list.scrollTop
- scrollNeed;
}
return;
}
$prev = $prev.prev();
}
};
$textInput.bind("keypress", function(e) {
var $selected = undefined;
if ((13 == e.keyCode) && ($selected =
getSelected())) {
liClick.call($selected);
}
if (40 == e.keyCode) {
selectNext();
}
if (38 == e.keyCode) {
selectPrev();
}
});
});
};
if('static'==config.mode)
{
autocomplete(this);
}else if('local'==config.mode){
autocomplete(this);
}else if('ajax'==config.mode){
var $getSelect = this;
try{
if(typeof config.url=='undefined'){
throw new Error('Ajax mode must have url
property');
}
if(config.method.toLowerCase()!
='get'&&config.method.toLowerCase()!='post'){
throw new Error('method property must be
get or post');
}
$.ajax({
type:config.method,
url:config.url,
beforeSend: function(XMLHttpRequest){
//ShowLoading();
},
success: function(data, textStatus){
config.store = eval('('+data
+')');
autocomplete($getSelect);
},
complete: function(XMLHttpRequest,
textStatus){
//HideLoading();
},
error: function(){
//请求出错处理
}
});
}catch(e){
alert(e.message);
}
}
},
getComboValue:function(){
//var numargs = arguments.length;
return this.val();
}
});
})(jQuery);
使用的使用,只需要:
$("#test1").createCombo
({edit:true,mode:"ajax",url:"http://localhost:8060/JqueryPlug
/autoCompleteData.jsp",
emptyText:"--请选择--",emptyValueText:"---",
onChanged:function(value,text){},width:"100px"
,listWidthOffset:6});
edit: 对应的下拉列表框是否可以输入;
mode: 用ajax,xml,local
url: 读取数据的后台路径
emptyText:初始时候下拉列表显示的文字
emptyValueText:初始时候下拉列表的的值
onChanged:当选择项变化时候所触发的事件
listWidthOffset: 下拉列表相对于width 定义以后的便宜量
下面是所需要的CSS
.combo {
position:relative;
zoom:1;
white-space: nowrap;
height: 21px;
width: 146px;
border: 0;
margin: 0;
padding: 0;
}
.combo input {
margin: 0 0 0 0;
font:normal 12px tahoma, arial, helvetica, sans-serif;
padding:1px 3px;
background:#fff url(../images/text-bg.gif) repeat-x 0 0;
border:1px solid #B5B8C8;
height: 18px;
width: 129px;
line-height:18px;
vertical-align:middle;
}
.combo img {
width:17px;
height:21px;
border:0;
background:transparent url(../images/trigger.gif) no-
repeat 0 0;
cursor:pointer;
border-bottom: 1px solid #B5B8C8;
position:absolute;
top:0;
left: 129;
margin:0;
margin-top:0px ;
*margin-top:2px ;
padding:0;
}
.combo img:hover {
background-position: -17px 0;
}
.combo ul {
/*bottom: 0;*/
border: 1px solid #D9D9D9;
list-style-type: none;
width: 146px;
background: #FFFFFF;
padding: 0;
cursor: pointer;
overflow: hidden;
margin: 0;
z-index: 1;
}
.combo li {
padding-left: 5px;
font:normal 14px tahoma, arial, helvetica, sans-serif;
background-color: #FFFFFF;
}
最后编写页面测试:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/sorta-
combo.css" />
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8"/>
<script type="text/javascript" src="js/jquery-
1.7.1.js"></script>
<script type="text/javascript" src="js/jquery.sorta-
combo.js"></script>
<script type="text/javascript" src="js/usage.js"></script>
<script type="javascript">
$(document).ready(function() {
$("#test1").createCombo
({edit:true,mode:"ajax",url:"http://localhost:8060/JqueryPlug
/autoCompleteData.jsp",
emptyText:"--请选择--",emptyValueText:"---",
onChanged:function(value,text){},width:"100px"
,listWidthOffset:6});
$("#test2").createCombo
({edit:true,mode:"ajax",url:"http://localhost:8060/JqueryPlug
/autoCompleteData2.jsp",emptyText:"--请选
择--",onChanged:function (value,text){}});
});
function show(){
alert($("#test1").getComboValue());
alert($("#test2").getComboValue());
}
</script>
<title>Test</title>
<style type="text/css">
body {
padding-left: 10px;
font-family: "Times New Roman", Times, serif;
font-size: 15px;
}
</style>
</head>
<body>
<p>
<label for="future-combo">请选择:</label><br/>
<select
name="future-combo" size="1" id="test1">
</select>
<br/>
<select name="future-combo2" size="1" id="test2">
</select>
</p>
<input type="button" onclick="show()"
value="show"></input>
</body>
</html>
测试效果图:
我们在第二个下拉列表输入test,这时候出现test3 和test4
当输入test3时候 test4自动消失
点击Show按钮,通过调用$("#test1").getComboValue() ;可以得到选择的值。