基于prototype的输入自动提示autocomplete

对老外的加了修改,对中文的支持和条数的显示

原作者地址: http://www.devbridge.com/projects/autocomplete/

 

效果:

 autocomplete.jsView Code

 
var  Autocomplete  =   function (el, options){
  
this .el  =  $(el);
  
this .id  =   this .el.identify();
  
this .el.setAttribute( ' autocomplete ' , ' off ' );
  
this .suggestions  =  [];
  
this .data  =  [];
  
this .badQueries  =  [];
  
this .selectedIndex  =   - 1 ;
  
this .currentValue  =   this .el.value;
  
this .intervalId  =   0 ;
  
this .cachedResponse  =  [];
  
this .instanceId  =   null ;
  
this .onChangeInterval  =   null ;
  
this .ignoreValueChange  =   false ;
  
this .serviceUrl  =  options.serviceUrl;
  
this .numbers  =  []; // 条数
   this .options  =  {
    autoSubmit:
false ,
    minChars:
1 ,
    maxHeight:
300 ,
    deferRequestBy:
0 ,
    width:
0 ,
    showNumber:
true // 是否显示条数
    container: null
  };
  
if (options){ Object.extend( this .options, options); }
  
if (Autocomplete.isDomLoaded){
    
this .initialize();
  }
else {
    Event.observe(document, 
' dom:loaded ' this .initialize.bind( this ),  false );
  }
};

Autocomplete.instances 
=  [];
Autocomplete.isDomLoaded 
=   false ;

Autocomplete.getInstance 
=   function (id){
  
var  instances  =  Autocomplete.instances;
  
var  i  =  instances.length;
  
while (i -- ){  if (instances[i].id  ===  id){  return  instances[i]; }}
};

Autocomplete.highlight 
=   function (value, re){
  
return  value.replace(re,  function (match){  return   ' <strong> '   +  match  +   ' <\/strong> '  });
};

Autocomplete.prototype 
=  {

  killerFn: 
null ,

  initialize: 
function () {
    
var  me  =   this ;
    
this .killerFn  =   function (e) {
      
if  ( ! $(Event.element(e)).up( ' .autocomplete ' )) {
        me.killSuggestions();
        me.disableKillerFn();
      }
    } .bindAsEventListener(
this );

    
if  ( ! this .options.width) {  this .options.width  =   this .el.getWidth(); }

    
var  div  =   new  Element( ' div ' , { style:  ' position:absolute; '  });
    div.update(
' <div class="autocomplete-w1"><div class="autocomplete-w2"><div class="autocomplete" id="Autocomplete_ '   +   this .id  +   ' " style="display:none; width: '   +   this .options.width  +   ' px;"></div></div></div> ' );

    
this .options.container  =  $( this .options.container);
    
if  ( this .options.container) {
      
this .options.container.appendChild(div);
      
this .fixPosition  =   function () { };
    } 
else  {
      document.body.appendChild(div);
    }

    
this .mainContainerId  =  div.identify();
    
this .container  =  $( ' Autocomplete_ '   +   this .id);
    
this .fixPosition();
    
    Event.observe(
this .el, window.opera  ?   ' keypress ' : ' keydown ' this .onKeyPress.bind( this ));
    Event.observe(
this .el,  ' keyup ' this .onKeyUp.bind( this ));
    Event.observe(
this .el,  ' blur ' this .enableKillerFn.bind( this ));
    Event.observe(
this .el,  ' focus ' this .fixPosition.bind( this ));
    
this .container.setStyle({ maxHeight:  this .options.maxHeight  +   ' px '  });
    
this .instanceId  =  Autocomplete.instances.push( this -   1 ;
  },

  fixPosition: 
function () {
    
var  offset  =   this .el.cumulativeOffset();
    $(
this .mainContainerId).setStyle({ top: (offset.top  +   this .el.getHeight())  +   ' px ' , left: offset.left  +   ' px '  });
  },

  enableKillerFn: 
function () {
    Event.observe(document.body, 
' click ' this .killerFn);
  },

  disableKillerFn: 
function () {
    Event.stopObserving(document.body, 
' click ' this .killerFn);
  },

  killSuggestions: 
function () {
    
this .stopKillSuggestions();
    
this .intervalId  =  window.setInterval( function () {  this .hide();  this .stopKillSuggestions(); } .bind( this ),  300 );
  },

  stopKillSuggestions: 
function () {
    window.clearInterval(
this .intervalId);
  },

  onKeyPress: 
function (e) {
    
if  ( ! this .enabled) {  return ; }
    
switch  (e.keyCode) {
      
case  Event.KEY_ESC:
        
this .el.value  =   this .currentValue;
        
this .hide();
        
break ;
      
case  Event.KEY_TAB:
      
case  Event.KEY_RETURN:
        
if  ( this .selectedIndex  ===   - 1 ) {
          
this .hide();
          
return ;
        }
        
this .select( this .selectedIndex);
        
if  (e.keyCode  ===  Event.KEY_TAB) {  return ; }
        
break ;
      
case  Event.KEY_UP:
        
this .moveUp();
        
break ;
      
case  Event.KEY_DOWN:
        
this .moveDown();
        
break ;
      
default :
        
return ;
    }
    Event.stop(e);
  },

  onKeyUp: 
function (e) {
    
switch  (e.keyCode) {
      
case  Event.KEY_UP:
      
case  Event.KEY_DOWN:
        
return ;
    }
    clearInterval(
this .onChangeInterval);
    
if  ( this .currentValue  !==   this .el.value) {
      
if  ( this .options.deferRequestBy  >   0 ) {
        
//  Defer lookup in case when value changes very quickly:
         this .onChangeInterval  =  setInterval(( function () {
          
this .onValueChange();
        }).bind(
this ),  this .options.deferRequestBy);
      } 
else  {
        
this .onValueChange();
      }
    }
  },

  onValueChange: 
function () {
    clearInterval(
this .onChangeInterval);
    
this .currentValue  =   this .el.value;
    
this .selectedIndex  =   - 1 ;
    
if  ( this .ignoreValueChange) {
      
this .ignoreValueChange  =   false ;
      
return ;
    }
    
if  ( this .currentValue  ===   ''   ||   this .currentValue.length  <   this .options.minChars) {
      
this .hide();
    } 
else  {
      
this .getSuggestions();
    }
  },

  getSuggestions: 
function () {
    
var  cr  =   this .cachedResponse[ this .currentValue];
    
if  (cr  &&  Object.isArray(cr.suggestions)) {
      
this .suggestions  =  cr.suggestions;
      
this .data  =  cr.data;
      
this .numbers  =  cr.numbers;
      
this .suggest();
    } 
else   if  ( ! this .isBadQuery( this .currentValue)) {
      
new  Ajax.Request( this .serviceUrl, {
        parameters: { query: 
this .currentValue },
        onComplete: 
this .processResponse.bind( this ),
        method: 
' get '
      });
    }
  },

  isBadQuery: 
function (q) {
    
var  i  =   this .badQueries.length;
    
while  (i -- ) {
      
if  (q.indexOf( this .badQueries[i])  ===   0 ) {  return   true ; }
    }
    
return   false ;
  },

  hide: 
function () {
    
this .enabled  =   false ;
    
this .selectedIndex  =   - 1 ;
    
this .container.hide();
  },

  suggest: 
function () {
    
if  ( this .suggestions.length  ===   0 ) {
      
this .hide();
      
return ;
    }
    
var  content  =  [];
    
var  re  =   new  RegExp( ' \\b '   +   this .currentValue.match( / [\u4e00-\u9fa5a-zA-Z0-9]+ / g).join( ' |\\b ' ),  ' gi ' );
    
var  numbersContent  =   '' ;
    
this .suggestions.each( function (value, i) {
      
if  (Object.isArray( this .numbers)  &&   this .options.showNumber){
        numbersContent 
=   '  <span class="number">约 '   +   this .numbers[i]  +   ' 条</span> ' ;
      }
      content.push((
this .selectedIndex  ===  i  ?   ' <div class="selected" '  :  ' <div ' ),  '  title=" ' , value,  ' " οnclick="Autocomplete.instances[ ' this .instanceId,  ' ].select( ' , i,  ' );" οnmοuseοver="Autocomplete.instances[ ' this .instanceId,  ' ].activate( ' , i,  ' );"> ' , Autocomplete.highlight(value, re), numbersContent,  ' </div> ' );
    } .bind(
this ));
    
this .enabled  =   true ;
    
this .container.update(content.join( '' )).show();
  },

  processResponse: 
function (xhr) {
    
var  response;
    
try  {
      response 
=  xhr.responseText.evalJSON();
      
if  ( ! Object.isArray(response.data)) { response.data  =  []; }
    } 
catch  (err) {  return ; }
    
this .cachedResponse[response.query]  =  response;
    
if  (response.suggestions.length  ===   0 ) {  this .badQueries.push(response.query); }
    
if  (response.query  ===   this .currentValue) {
      
this .suggestions  =  response.suggestions;
      
this .data  =  response.data;
      
this .numbers  =  response.numbers;
      
this .suggest(); 
    }
  },

  activate: 
function (index) {
    
var  divs  =   this .container.childNodes;
    
var  activeItem;
    
//  Clear previous selection:
     if  ( this .selectedIndex  !==   - 1   &&  divs.length  >   this .selectedIndex) {
      divs[
this .selectedIndex].className  =   '' ;
    }
    
this .selectedIndex  =  index;
    
if  ( this .selectedIndex  !==   - 1   &&  divs.length  >   this .selectedIndex) {
      activeItem 
=  divs[ this .selectedIndex]
      activeItem.className 
=   ' selected ' ;
    }
    
return  activeItem;
  },

  deactivate: 
function (div, index) {
    div.className 
=   '' ;
    
if  ( this .selectedIndex  ===  index) {  this .selectedIndex  =   - 1 ; }
  },

  select: 
function (i) {
    
var  selectedValue  =   this .suggestions[i];
    
if  (selectedValue) {
      
this .el.value  =  selectedValue;
      
if  ( this .options.autoSubmit  &&   this .el.form) {
        
this .el.form.submit();
      }
      
this .ignoreValueChange  =   true ;
      
this .hide();
      
this .onSelect(i);
    }
  },

  moveUp: 
function () {
    
if  ( this .selectedIndex  ===   - 1 ) {  return ; }
    
if  ( this .selectedIndex  ===   0 ) {
      
this .container.childNodes[ 0 ].className  =   '' ;
      
this .selectedIndex  =   - 1 ;
      
this .el.value  =   this .currentValue;
      
return ;
    }
    
this .adjustScroll( this .selectedIndex  -   1 );
  },

  moveDown: 
function () {
    
if  ( this .selectedIndex  ===  ( this .suggestions.length  -   1 )) {  return ; }
    
this .adjustScroll( this .selectedIndex  +   1 );
  },

  adjustScroll: 
function (i) {
    
var  container  =   this .container;
    
var  activeItem  =   this .activate(i);
    
var  offsetTop  =  activeItem.offsetTop;
    
var  upperBound  =  container.scrollTop;
    
var  lowerBound  =  upperBound  +   this .options.maxHeight  -   25 ;
    
if  (offsetTop  <  upperBound) {
      container.scrollTop 
=  offsetTop;
    } 
else   if  (offsetTop  >  lowerBound) {
      container.scrollTop 
=  offsetTop  -   this .options.maxHeight  +   25 ;
    }
    
this .el.value  =   this .suggestions[i];
  },

  onSelect: 
function (i) {
    (
this .options.onSelect  ||  Prototype.emptyFunction)( this .suggestions[i],  this .data[i]);
  }

};

Event.observe(document, 
' dom:loaded ' function (){ Autocomplete.isDomLoaded  =   true ; },  false

 

使用:Event.observe(window, 'load'function() {

     function  onAutocompleteSelect(value, data){
            
// ..
    }
    
var  rand  =   new  Date().getTime();
    
var  url  =   ' data.js?r= '   +  rand;
    
new  Autocomplete( ' txtEmployeeNum ' , { 
        serviceUrl: url, 
        width: 
300 ,   // 可选
        onSelect: onAutocompleteSelect,  // 可选
        showNumber:  true   // 显示条数
         // container: 'ac_container'  //可选
    });
});

< input type = " text "  name = " q "  id = " txtEmployeeNum "   / >
<!--   < div id = " ac_container " >< / div>  -->  

 

data.js 有后台控制,产生json格式数据,如下:

 

// {query:'z',suggestions:['z','z1','z2','z3']}

//{query:'q',suggestions:['q','q1','q2','q3'],numbers:[99,88,77,66]}

{query:'',suggestions:['','去1','去12','去123'],numbers:[99,88,77,66]}

 

弹出提示层的原型:View Code

 
< div  class ="autocomplete-w1" >
  
< div  class ="autocomplete-w2" >
    
< div  style ="width:299px;"  id ="Autocomplete_query"  class ="autocomplete" >
      
< div  class ="selected" >< strong > Li </ strong > thuania < span  class ="number" > 约88个服务 </ span ></ div >
    
</ div >
  
</ div >
</ div

 

 css控制样式自己控制:View Code

 
.autocomplete-w1  {  background : url(img/shadow.png) no-repeat bottom right ;  position : absolute ;  top : 4px ;  left : 3px ;   /*  IE6 fix:  */  _background : none ;  _top : 1px ;   }
.autocomplete 
{  width : 300px ;  border : 1px solid #999 ;  background : #FFF ;  cursor : default ;  text-align : left ;  max-height : 350px ;  overflow : auto ;  margin : -6px 6px 6px -6px ;   /*  IE specific:  */  _height : 350px ;   _margin : 0px 6px 6px 0 ;  overflow-x : hidden ;   }
.autocomplete .selected 
{  background : #F0F0F0 ;   }
.autocomplete div 
{  padding : 2px 5px ;  white-space : nowrap ;   }
.autocomplete strong 
{  font-weight : normal ;  color : #3399FF ;   }
.autocomplete .number 
{  font-weight : normal ;  color : red ;  

转载于:https://www.cnblogs.com/chthp/archive/2011/07/07/2100269.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值