asp教程.net autocomplete组件实现详解方法
combobox组件(autocomplete组件)
(function(){
var mix=function(des, src){
for(var i in src){
des[i] = src[i];
}
},
//domu=qw.domu,
createelement=function (tagname, property) {
var el = document.createelement(tagname);
if (property) {
for (var i in property) el[i] = property[i];
}
return el;
},
//eventh=qw.eventh,
target=function(e) {
e=e||window.event;
return e.target || e.srcelement;
},
keycode=function(e) {
e=e||window.event;
return e.which || e.keycode || e.charcode;
},
preventdefault=function(e) {
e=e||window.event;
e.preventdefault && e.preventdefault() || (e.returnvalue = false);
},
//custevent=qw.custevent,
//nodeh=qw.nodeh,
hasclass=function(el, cn) {
return new regexp('(?:^|s)' +cn+ '(?:s|$)','i').test(el.classname);
},
addclass=function (el, cn) {
if (!hasclass(el, cn)) {
el.classname = (el.classname + ' '+cn).replace(/^s+|s+$/g,"");
}
},
removeclass=function (el, cn) {
if (hasclass(el, cn)) {
el.classname = el.classname.replace(new regexp('(?:s|^)' +cn+ '(?:s|$)','i'),' ').replace(/^s+|s+$/g,"");
}
},
//setstyle=nodeh.setstyle,
//getxy=nodeh.getxy, 由于getxy的兼容代码很长,所以无依赖化时,稍稍调整下,不用位置,而改用dom结构来定位
ancestornode=function(el,tagname){
while(el=el.parentnode){
if(el.tagname==tagname) return el;
}
return null;
},
on=function (element, name, handler) {
element.addeventlistener && element.addeventlistener(name, handler, false)
|| element.attachevent && element.attachevent('on' + name, handler);
},
isie=(/msie/i).test(navigator.useragent);
function encode4html(s){
var o=[/&/g,/"/g,/'/g,//g];
var n=["&",""","'","<",">"];
for(var i=0;i{
s=s.replace(o[i],n[i]);
}
return s;
};
/**
*@class combobox 可输入下拉框
*/
function combobox(opts){
mix(this,opts,1);
if(!this.lazyrender) this.render();
}
combobox.events=["enter","selectitem"];combobox.prototype={
/*
*参数
*/
width:0,
otext: null,//text-input对象
itemsdata:null,//items数据,array,需要在refreshdata方法里进行设值
minfilterlen:1,//最小filter长度。当otext.value不小于此值时,才会有suggest效果
/*
*开放的变量,readonly的
*/
omenu:null,
otoolbar:null,//控制行,目前只有关闭按钮
owrap:null,
selectedindex:-1,//当前选中项
filteredvalue:"",//过滤值。过滤动作已完成
filteringvalue:"",//过滤值。过滤动作正在进行(因为有时过滤是异步的)
acvalue:"",//通过自动完成得到的值
disabled:false,//suggest是否处于禁止状态。--由页面逻辑决定
closed:false,//suggest是否处于关闭状态。--由suggest自身决定
/*
*方法
*/
show: function(){
if(this.omenu.rows.length){
this.owrap.style.display="";
//var xy=getxy(this.otext);
//setstyle(this.owrap,{top:xy[1]+this.otext.offsetheight+"px",left:xy[0]+"px",display:""});
}
},
hide: function(){
this.owrap.style.display="none";
},
refreshitems: function(){
var me=this;
var data=me.itemsdata;
if(data && !data.__isitemsdatarendered){ //加上属性“__isitemsdatarendered”以标志data是否已经render成html
var html=[];
for(var i=0;i//var datatype=data[i].constructor;
//if(datatype==string){//为string时,则字符串既是value,也是html
// html.push(''); '+encode4html(data[i])+'
//}
//else if(datatype==array){//为array时,则第一个元素为value,第二个元素为html
html.push(''); '+data[i][1]+'
//}
//else{//为object时,则其格式为{value:"aaab",html:"aaab"}
// html.push(''); '+data[i]["html"]+'
//}
html.push("");
}
me._setmenuinnerhtml(html.join("").replace(/(if(data.length) me.show();
else me.hide();
me.filteredvalue=me.filteringvalue;
me.acvalue="";
me.selectedindex=-1;
data.__isitemsdatarendered=true;
}
},
refreshdata:function(){
this.itemsdata=["refreshdata一定要重写!"];
},
setselectedindex:function(idx,needblur){
var me=this;
var rows=me.omenu.rows;
if(rows.length){
if(me.selectedindex>-1) removeclass(rows[me.selectedindex],"selected");
idx=(idx+rows.length+1)%(rows.length+1);
if(idx==rows.length){
me.acvalue=me.otext.value=me.filteringvalue;//这里用filteringvalue,而不用filteredvalue,是因为有时itemsdata是静态的(例如,不用过滤功能的单纯combobox)
idx=-1;
}
else {
me.acvalue=me.otext.value=rows[idx].getattribute("acvalue");
addclass(rows[idx],"selected");
}
}
else{
idx=-1;
}
me.selectedindex=idx;
},
_setmenuinnerhtml:function(html){
var div=createelement("div",{innerhtml:""+html+"
"});
var rows=div.firstchild.rows;
var omenu=this.omenu;
for (var i=omenu.childnodes.length-1;i>=0;i--) omenu.removechild(omenu.childnodes[i]);
while(rows.length) {
omenu.appendchild(rows[0]);
}
},
render: function(){
var me=this;
if(me._rendered) return ;
me._rendered=true;
//custevent.createevents(me,combobox.events);
var owrap=createelement("div",{classname:"ac_wrap",innerhtml:''.replace(/(//var b=document.body;
//b.insertbefore(owrap,b.firstchild);
var otext=me.otext;
otext.parentnode.insertbefore(owrap,otext);//为了减少定位麻烦,改用dom位置来定位
var els=owrap.getelementsbytagname("tbody");
var otoolbar=me.otoolbar=els[1], omenu=me.omenu=els[0];
otext.setattribute("autocomplete","off");//一定要用setattrubute,否则会导致在firefox里半输入状态下执行otext.blur()时会抛出无法捕捉的异常。
var w=(me.width || me.otext.offsetwidth)+"px";
if(isie) owrap.style.width=w;
else owrap.style.minwidth=w;
owrap.style.top=otext.offsetheight+'px';
me.owrap=owrap;
me.hide();
on(me.otext,"dblclick",function(e){//监控otext的事件
if(me.disabled || otext.value.lengthif(me.closed=!me.closed) me.hide();
else me.show();
});
on(me.otext,"keydown",function(e){//监控otext的事件
if(me.disabled) return;
var kcode=keycode(e);
var dir=0;
switch(kcode){
case 40 : dir=1;break;
case 38 : dir=-1;break;
case 27 : if(!me.closed){me.hide();me.closed=true;preventdefault(e)} break;//隐藏suggest
case 13 : me.hide();me.onenter && me.onenter(); break;//隐藏suggest
}
if(dir && otext.value.length>=me.minfilterlen){
preventdefault(e);
if(owrap.style.display=="none"){
me.show();
me.closed=false;
}
else{
me.setselectedindex(me.selectedindex+dir);
}
}
});
on(me.otext,"focus",function(e){//监控otext的事件
if(me.disabled) return;
if(me._refreshtimer) clearinterval(me._refreshtimer);
me._refreshtimer=setinterval(function(){
var val=otext.value;
if(val.lengthme.acvalue=me.filteringvalue=me.filteredvalue="";
me.hide();
me.closed=false;//吸收google suggest的策略:如果suggest被关闭,用户将otext清空,这时会将suggest打开。
}
else if(!me.closed){
if(val != me.filteredvalue && val != me.filteringvalue && val != me.acvalue){
me.filteringvalue=val;
me.refreshdata();
}
if(me.itemsdata){
me.refreshitems();
}
}
},100);
});
on(me.otext,"blur",function(e){//监控otext的事件
me.hide();
clearinterval(me._refreshtimer);
});
owrap.onmousedown=function(e){//监控owrap的事件
if(isie){otext.setcapture();settimeout(function(){otext.releasecapture();},10);} //解决“ie下,半输入状态时不能点击选项”的问题
preventdefault(e);
};
omenu.onclick=function(e){//监控omenu的事件
var el=target(e);
var tr=ancestornode(el,"tr");
if(tr) {
otext.blur();//firefox下半输入法输入时,选择item,console有错,无法catch,并且不影响运行。
settimeout(function(){otext.focus();},10);//解决“半输入状态时不能点击选项”的问题
me.setselectedindex(tr.rowindex,true);
me.hide();
me.onselectitem && me.onselectitem();
}
};
omenu.onmouseover=function(e){//监控omenu的事件
var el=target(e);
var tr=ancestornode(el,"tr");
if(tr) addclass(tr,"mouseover");
};
omenu.onmouseout=function(e){//监控omenu的事件
var el=target(e);
var tr=ancestornode(el,"tr");
if(tr) removeclass(tr,"mouseover");
};
otoolbar.getelementsbytagname("a")[0].onclick=function(e){//监控close按钮的事件
me.closed=true;
me.hide();
preventdefault(e);
};
}
}window.combobox=combobox;
})();
function g(a){return document.getelementbyid(a);};
function getscript(d,a){var e=document.getelementsbytagname("head")[0],c=document.createelement("script"),b=false;c.src=d;c.onerror=c.onload=c.onreadystatechange=function(){if(!b&&(!this.readystate||this.readystate=="loaded"||this.readystate=="complete")){b=true;a&&a();c.onerror=c.onload=c.onreadystatechange=null;e.removechild(c);}};e.appendchild(c);};
function foreach(b,a){for(var c=0;cwindow.sugcb =function (data){
var ar=[],
baidudata=data.s||[],
kw=g("kw").value;
for(var i=0;ivar key=baidudata[i],
val=key;
if(kw && val.indexof(kw)==0){
val=kw+''+val.substr(kw.length)+'';
}
if(key) ar.push([key,val]);
}
cb.itemsdata=ar;
};var cb=new combobox({otext:g("kw"),
onselectitem:function(){g('su').click();},
refreshdata:function(){
getscript("http://suggestion.baidu.com/su?p=3&cb=window.sugcb&t=1286453644402&wd="+
encodeuricomponent(this.otext.value));
}});