Kissy自動完成組件AutoComplete(仿淘寶搜索)

 

效果圖:效果圖

 

  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  5. <META HTTP-EQUIV="Pragma" CONTENT="no-cache">  
  6. <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">  
  7. <META HTTP-EQUIV="Expires" CONTENT="0">  
  8. <title>AutoComplete DEMO</title>  
  9. <style type="text/css">  
  10. /*****************************************************************************/  
  11. /*                                  reset css                                */  
  12. /*****************************************************************************/  
  13. html,body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td {  
  14.     margin: 0;  
  15.     padding: 0;  
  16. }  
  17.   
  18. img,body,html {  
  19.     border: 0;  
  20. }  
  21.   
  22. address,caption,cite,code,dfn,em,th,var {  
  23.     font-style: normal;  
  24.     font-weight: normal;  
  25. }  
  26.   
  27. ol,ul {  
  28.     list-style: none;  
  29. }  
  30.   
  31. caption,th {  
  32.     text-align: left;  
  33. }  
  34.   
  35. h1,h2,h3,h4,h5,h6 {  
  36.     font-size: 100%;  
  37. }  
  38.   
  39. h1 {  
  40.     font-size: 18px;  
  41. }  
  42.   
  43. h2 {  
  44.     font-size: 16px;  
  45. }  
  46.   
  47. h3 {  
  48.     font-size: 14px;  
  49. }  
  50.   
  51. q:before,q:after {  
  52.     content: '';  
  53. }  
  54.   
  55. sup {  
  56.     vertical-align: text-top;  
  57. }  
  58.   
  59. sub {  
  60.     vertical-align: text-bottom;  
  61. }  
  62.   
  63. input,button,textarea,select {  
  64.     font-family: inherit;  
  65.     font-size: inherit;  
  66.     font-weight: inherit;  
  67. }  
  68.   
  69. input,button,textarea,select {  
  70.     *font-size: 100%;  
  71. }  
  72.   
  73. select,input,button,textarea {  
  74.     font: 100% tahoma, helvetica, arial, sans-serif;  
  75. }  
  76.   
  77. table {  
  78.     font-size: inherit;  
  79.     font: 100%;  
  80. }  
  81.   
  82. pre,code,kbd,samp,tt {  
  83.     font-family: 'courier new', courier, monospace;  
  84. }  
  85.   
  86. small {  
  87.     font-size: 100%;  
  88. }  
  89.   
  90. a {  
  91.     color: #028ef0;  
  92.     text-decoration: none;  
  93. }  
  94.   
  95. a:hover {  
  96.     color: #f60;  
  97.     text-decoration: underline;  
  98. }  
  99.   
  100. abbr,acronym {  
  101.     border-bottom: 1px dotted;  
  102.     cursor: help;  
  103. }  
  104.   
  105. ins {  
  106.     text-decoration: none;  
  107. }  
  108.   
  109. del {  
  110.     text-decoration: line-through;  
  111. }  
  112.   
  113. hr {  
  114.     color: #d1d7dc;  
  115.     background-color: #d1d7dc;  
  116.     border: none;  
  117.     height: 1px;  
  118. }  
  119.   
  120. /* 讓瀏覽器默認也顯示垂直滾動條,防止因滾動條引起的閃爍 */  
  121. html {  
  122.       overflow-y: scroll;  
  123. }  
  124.   
  125. body {  
  126.     font: 12px/ 1.5 Tahoma, Arial, '宋體', sans-serif;  
  127.     background-color: #fff;  
  128. }  
  129. .clearfix:after {  
  130.       visibility: hidden;  
  131.       display: block;  
  132.       font-size: 0;  
  133.       content: " ";  
  134.       clear: both;  
  135.       height: 0;  
  136. }  
  137. .clearfix{  
  138.       *zoom:1;  
  139. }  
  140.   
  141. /*****************************************************************************/  
  142. /*                                 autocompelete css                                */  
  143. /*****************************************************************************/  
  144. .k-autocomplete-txt{  
  145.     outline: none;    
  146.     padding: 0px;  
  147.     background: none;  
  148. }  
  149. .k-autocomplete-wrapper{  
  150.     position:absolute;  
  151.     z-index: 9999;  
  152. }  
  153. .k-autocomplete-wrapper li{  
  154.     padding:0px;  
  155.     margin:0px;  
  156.     display: block;  
  157.     padding:2px 5px;  
  158.     font-size: 12px;  
  159.     height:18px;  
  160.     line-height: 18px;  
  161.     cursor: default;  
  162. }  
  163. .k-autocomplete-key{  
  164.       
  165. }  
  166. .k-autocomplete-val{  
  167.     display: block;  
  168.     float: right;  
  169.     color:green;  
  170. }  
  171. .k-autocomplete-wrapper li.sel{  
  172.     background: #227AFF;  
  173.     color:#fff;  
  174. }  
  175. .k-autocomplete-wrapper li.sel .k-autocomplete-val{  
  176.     color:#fff;  
  177. }  
  178. .k-autocomplete-tip{  
  179.     position: absolute;  
  180.     z-index: -1;  
  181.     text-indent: 4px;  
  182.     color:#ccc;  
  183. }  
  184.   
  185. /*****************************************************************************/  
  186. /*                                 other css                                */  
  187. /*****************************************************************************/  
  188.   
  189. .txt{  
  190.     width:400px;  
  191.     margin-left: 200px;  
  192.     margin-top: 100px;  
  193.     text-indent: 2px;  
  194.     height:20px;  
  195.     border: 1px solid #ccc;  
  196.     line-height: 20px;  
  197. }  
  198. .btn{  
  199.     width:100px;  
  200.     height:24px;  
  201. }  
  202. </style>  
  203. </head>  
  204. <body>  
  205. <input type="text"  id="demo" value="" class='txt'/><input type="button"  class='btn' value="搜索"/>  
  206. <script src="http://a.tbcdn.cn/s/kissy/1.2.0/kissy.js"></script>  
  207. <script type="text/javascript" src='js/kissy-autocomplete.js'>  
  208. /**  
  209.  * AutoComplete V0.1  
  210.  * @author huxiaoqi  
  211.  */  
  212. (function(S){  
  213.     var $ = S.all,  
  214.         Event = S.Event,  
  215.         IO = S.IO,  
  216.         UA = S.UA;  
  217. /**  
  218.  * TODO 定義全局變量  
  219.  * @param $WRAPPER 容器對象  
  220.  * @param PREFIX 組件前綴  
  221.  * @param WRAPPER_CLS Wrapper類名  
  222.  * @param WRAPPER_TPL Wrapper模板  
  223.  * @param TXT_CLS 文本框類名  
  224.  * @param TIP_CLS 提示框類名  
  225.  * @param $TIP_TPL 提示框模板對象  
  226.  * @param CONFIG 默認配置  
  227.  * @param KEY_MAP 按鈕配置  
  228.  * @returns AutoComplete  
  229.  */  
  230.     S.add("AutoComplete",function(){  
  231.         var $WRAPPER,PREFIX = "k-autocomplete-",  
  232.             WRAPPER_CLS = PREFIX+"wrapper";  
  233.             WRAPPER_TPL = "<ul class="+WRAPPER_CLS+"></ul>",  
  234.             TXT_CLS = PREFIX+"txt",  
  235.             TIP_CLS = PREFIX+"tip",  
  236.             $TIP_TPL = $("<div class="+TIP_CLS+"></div>"),  
  237.             KEY_CLS = PREFIX+"key",  
  238.             VAL_CLS = PREFIX+"val";  
  239.             //定義初始配置  
  240.             CONFIG = {  
  241.                     tip:"input some thing",  
  242.                     url:"",  
  243.                     type:"get",  
  244.                     target:"",  
  245.                     triggerLenth:2,  
  246.                     itemSize:5,  
  247.                     autoSubmit:true  
  248.             },  
  249.   
  250.             //定義按鍵  
  251.             KEY_MAP = {  
  252.                     ENTER:13,  
  253.                     UP:38,  
  254.                     DOWN:40,  
  255.                     LEFT:37,  
  256.                     RIGHT:39,  
  257.                     BACKSPACE:8,  
  258.                     SPACE:32  
  259.             };  
  260.   
  261.         function AutoComplete(cfg){  
  262.             var self = this;  
  263.               
  264.             if(!(self instanceof AutoComplete)){    //確保this指向AutoComplete實例  
  265.                 return new AutoComplete();  
  266.             }  
  267.             self.version = "0.1";   
  268.             //配置合併  
  269.             self.config = S.mix(CONFIG,cfg);  
  270.             //獲取渲染對象  
  271.             self.target = typeof self.config.target === "string" ? $(self.config.target) : self.config.target;  
  272.             //初始化  
  273.             self._init();  
  274.             //獲取wrapper  全局  
  275.             $WRAPPER = self._render();  
  276.             //綁定事件  
  277.             self._bindEvent();  
  278.         }  
  279.         //將屬性放入prototype  
  280.         S.augment(AutoComplete,{  
  281.             /**  
  282.              * TODO 初始化 tip 提示  
  283.              */  
  284.             _init:function(){     
  285.                     var self = this,  
  286.                     target = self.target,  
  287.                     position = target.offset(),  
  288.                     lineHeight;  
  289.                     target.addClass(TXT_CLS).val("");                     
  290.                     //IE 3px bug  
  291.                     lineHeight = UA.shell === "ie" ?  target.height()+3+"px" : target.height()+"px";  
  292.                     $TIP_TPL.html(self.config.tip)  
  293.                             .css({  
  294.                                     'left':position.left,  
  295.                                     'top':position.top,  
  296.                                     'height':target.height(),  
  297.                                     'width':target.width(),  
  298.                                     'line-height':lineHeight  
  299.                                 })  
  300.                             .insertBefore(target);  
  301.             },  
  302.             /**  
  303.              * TODO 渲染提示框  
  304.              * @returns NodeList  
  305.              */  
  306.             _render:function(){  
  307.                 var self = this,  
  308.                     target = self.target,  
  309.                     position = target.offset();  
  310.                 //將wrapper放入頁面  
  311.                 $(WRAPPER_TPL).width(target.width())  
  312.                               .css({  
  313.                                   "left":position.left,  
  314.                                   "top":position.top+target.height()  
  315.                                })  
  316.                                .insertBefore(target);  
  317.                 return $("."+WRAPPER_CLS);  
  318.             },  
  319.             /**  
  320.              * TODO 綁定事件  
  321.              * @returns null  
  322.              */  
  323.             _bindEvent:function(){  
  324.                 var self = this,$curItem,curIndex = -1;  
  325.                 //給文本框綁定事件  
  326.                 Event.on(self.target,"focus blur keyup",function(e){  
  327.                     var eeevtType = e.type,  
  328.                     keyCode = e.keyCode;  
  329.                     self.toggleTipHandler(e);  
  330.                     //觸發彈出層事件  
  331.                     Event.fire($WRAPPER,"keyup",e);  
  332.                     if(self.target.val() === "" || evtType === "blur"){  
  333.                         self.clear();  
  334.                     }  
  335.                 });  
  336.                   
  337.                 //綁定彈出層事件  
  338.                 Event.on($WRAPPER,"keyup",function(e){  
  339.                     var eeevtType = e.type,  
  340.                         keyCode = e.keyCode,  
  341.                         eeevtTarget = e.target,  
  342.                         triggerLenth = self.config.triggerLenth;  
  343.                         if(evtType == "keyup" && self.target.val().length >= triggerLenth){                           
  344.                             if(self.isAlphaKey(keyCode) || self.isNumberKey(keyCode) || keyCode == KEY_MAP.BACKSPACE || keyCode == KEY_MAP.SPACE){  
  345.                                 self.autoCompleteHandler(e);                              
  346.                             }else if(self.isDirectionKey(e.keyCode)){  
  347.                                 !self.isNotNull() ? self.autoCompleteHandler(e) : null;  
  348.                                 //判定爲方向鍵  
  349.                                 var $items = $WRAPPER.children(),  
  350.                                       size = $items.length;  
  351.                                 //獲取當前選中索引    
  352.                                 curIndex = self.getSelectedItem();    
  353.                                 if(keyCode == KEY_MAP.DOWN){  
  354.                                     curIndexcurIndexcurIndex = curIndex >= size-1 ?0 : curIndex+1;                                
  355.                                 }else if(keyCode == KEY_MAP.UP){  
  356.                                     curIndexcurIndexcurIndex = curIndex <= 0 ? size-1 : curIndex-1;  
  357.                                 }     
  358.                                 $curItem = self.selectItem($items[curIndex]);  
  359.                                 //回車選中當前選項  
  360.                                 $curItem.all('span')[0]?self.target.val($curItem.all('span')[0].innerHTML):self.target.val($curItem.text());                                  
  361.                             }else if(keyCode == KEY_MAP.ENTER && $curItem){  
  362.                                 //清空內容  
  363.                                 self.clear();  
  364.                             }  
  365.                         }  
  366.                 });  
  367.             },  
  368.             /**  
  369.              * TODO 返回數據後綁定mouseenter mousedown事件  
  370.              * @returns null  
  371.              */  
  372.             _bindItemEvent:function(){  
  373.                 var self = this;  
  374.                 return function(){  
  375.                     Event.on($WRAPPER.children(),"mouseenter mousedown",function(e){  
  376.                         var eeevtType = e.type,  
  377.                             eeevtTarget = e.target;  
  378.                         $(evtTarget).addClass('sel').siblings().removeClass('sel');   
  379.                         if(evtType == "mousedown"){  
  380.                             $(evtTarget).all('span')[0]?self.target.val($(evtTarget).all('span')[0].innerHTML):self.target.val($(evtTarget).text());  
  381.                             self.clear();  
  382.                         }  
  383.                     });  
  384.                 };  
  385.             },  
  386.             /**  
  387.              * TODO 處理提示文本  
  388.              *      僅通過color屬性toggle  
  389.              * @returns null  
  390.              */  
  391.             toggleTipHandler:function(e){  
  392.                 var self = this,  
  393.                     target = self.target,  
  394.                     eeevtType = e.type;  
  395.                 if(evtType == "focus"){  
  396.                     $TIP_TPL.css({"color":"#fff"});  
  397.                 }  
  398.                 else if(evtType == "blur" && self.target.val() == ""){  
  399.                     $TIP_TPL.css({"color":"#ccc"});  
  400.                 }  
  401.             },  
  402.             /**  
  403.              * TODO 處理獲取的數據 remote||local  
  404.              * @returns null  
  405.              */  
  406.             autoCompleteHandler:function(e){  
  407.                 var self = this,  
  408.                     config = self.config,  
  409.                     data = config.data;  
  410.                     url = config.url,  
  411.                     type = config.type,  
  412.                     itemSize = config.itemSize;  
  413.                 //若url不爲空 則默認爲 remote數據   否則爲local數據  
  414.                 if(url != ""){        
  415.                     IO({  
  416.                         url:url,  
  417.                         type:type,  
  418.                         data:{itemSize:itemSize,queryData:self.target.val()},  
  419.                         success:function(data){  
  420.                                 self.createDom(data,self._bindItemEvent());  
  421.                         }  
  422.                     });  
  423.                 }else{  
  424.                     self.createDom(data,self._bindItemEvent());  
  425.                 }  
  426.                   
  427.             },  
  428.             /**  
  429.              * TODO 獲取自動生成的dom內容  
  430.              * @param data,callback  
  431.              * @returns null  
  432.              */  
  433.             createDom:function(data,callback){  
  434.                 var self = this,  
  435.                 queryTxt = self.target.val(),  
  436.                 html = "";  
  437.                 if(data){  
  438.                     data = typeof data === "string"? eval("("+data+")"):data;  
  439.                     if(queryTxt !="" && data.items){          
  440.                         S.each(data.items,function(item){  
  441.                                 if(typeof item === "object" && item.key && item.val){  
  442.                                     html += "<li><span class="+KEY_CLS+">"+item.key+"</span><span class="+VAL_CLS+">"+item.val+"</span></li>";  
  443.                                 }else{  
  444.                                     html += "<li>"+item+"</li>";  
  445.                                 }     
  446.                         });  
  447.                     }  
  448.                     if(html != ""){  
  449.                         $WRAPPER.html(html).css({"border":"1px solid #ccc","border-top":"none"});  
  450.                         callback();  
  451.                     }else{  
  452.                         this.clear();  
  453.                     }  
  454.                 }     
  455.             },  
  456.               
  457.               
  458.             /**  
  459.              * TODO 方向鍵控制選中的內容  
  460.              * @returns Node  
  461.              */  
  462.             selectItem:function(item){  
  463.                 $(item).addClass('sel').siblings().removeClass('sel');    
  464.                 return $(item);  
  465.             },  
  466.             /**  
  467.              * TODO 獲取當前選中的內容  
  468.              * @returns int  
  469.              */  
  470.             getSelectedItem:function(){  
  471.                 var self = this,  
  472.                 $items = $WRAPPER.children(),  
  473.                 index = -1;  
  474.                 S.each($items,function(item,i){  
  475.                     if(item.className == "sel"){  
  476.                         iiindex = i;  
  477.                     }     
  478.                 });  
  479.                 return index;  
  480.             },  
  481.             /**  
  482.              * TODO 判斷是否爲方向鍵  
  483.              * @param keyCode  
  484.              * @returns boolean  
  485.              */  
  486.             isDirectionKey:function(keyCode){  
  487.                 var keyMap = KEY_MAP;  
  488.                 if(keyCode == keyMap.UP || keyCode == keyMap.DOWN || keyCode == keyMap.LEFT || keyCode == keyMap.RIGHT){  
  489.                     return true;  
  490.                 }  
  491.                 return false;  
  492.             },  
  493.             /**  
  494.              * TODO 判斷是否爲字母鍵  
  495.              * @param keyCode  
  496.              * @returns boolean  
  497.              */  
  498.             isAlphaKey:function(keyCode){  
  499.                 return keyCode >= 65 && keyCode <=90 ? true:false;  
  500.             },  
  501.             /**  
  502.              * TODO 判斷是否爲數字鍵  
  503.              * @param keyCode  
  504.              * @returns boolean  
  505.              */  
  506.             isNumberKey:function(keyCode){  
  507.                 return (keyCode >= 48 && keyCode <= 57) ||  (keyCode >= 96 && keyCode <= 105) ? true:false;  
  508.             },  
  509.             clear:function(){  
  510.                 $WRAPPER.html("").css({"border":"none"});  
  511.             },  
  512.             /**  
  513.              * TODO 判斷提示是否爲空  
  514.              * @returns boolean  
  515.              */  
  516.             isNotNull:function(){  
  517.                 return $WRAPPER.html() != "";  
  518.             }  
  519.         });  
  520.         return AutoComplete;  
  521.     });  
  522. })(KISSY);  
  523.   
  524. </script>  
  525. <script type="text/javascript">  
  526. (function(S){  
  527.     S.use("AutoComplete",function(S,AutoComplete){  
  528.         var auto = new AutoComplete({  
  529.                 tip:"請輸入內容",  
  530.                 url:"",  
  531.                 target:"#demo",  
  532.                 triggerLenth:1,  
  533.                 /**  
  534.                  * items 可爲 {key:"",val:""}的形式  也可爲 string  
  535.                  */  
  536.                 data:{  
  537.                     items:[  
  538.                         {key:"aaaa",val:"約1000條記錄"},  
  539.                         {key:'試試看',val:"約50條記錄"},  
  540.                         {key:'java',val:"約2000條記錄"},  
  541.                         {key:'這個是中文',val:"約1300條記錄"},  
  542.                         {key:'javascript',val:"約200條記錄"},  
  543.                         {key:'kissy',val:"約11200條記錄"},  
  544.                         {key:'jquery',val:"約1000條記錄"},  
  545.                         {key:'java開發指南',val:"約1200條記錄"},  
  546.                         {key:'java文檔',val:"約100條記錄"},  
  547.                         {key:'1234',val:"約400條記錄"},  
  548.                         "這個是string"  
  549.                     ]}    
  550.             });  
  551.           
  552.     });  
  553. })(KISSY);  
  554. </script>  
  555. </body>  
  556. </html>  
  557.   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章