首页 > 代码库 > 自己手写的自动完成js类

自己手写的自动完成js类

  在web开发中,为了提高用户体验,会经常用到输入框的自动完成功能,不仅帮助用户进行快速输入,最重要的是帮助那些“记不全要输入什么”的用户进行选择。这个功能有很多插件已经实现了,为了适应项目的特殊需求,决定自己编写一个具备通用性、扩展性和灵活性的自动完成类,就当是边写边学习了,一举两得。该功能是比较简单的,核心是数据获取方式和导航的实现,简单写了一个,经测试非常好用,还有很多地方需要修改和改进,例如:在原型中只暴露init方法即可,其他方法都需要放到私有空间内,不让用户访问到,这个以后再完善吧。啥也不说了,小二,上菜:

  1 /**  2  * 实现自动完成功能的js类  3  * 1、数据获取方式:设置静态数据集、ajax方式、自定义数据获取函数  4  * 2、可以控制是否启用匹配项的循环选择  5  * 3、可以控制是否使用默认静态数据集,在获取动态数据失败的情况下会显示  
7
*/ 8 9 (function(){ 10 11 //封装使用频繁的变量,在构造函数中进行初始化 12 var commonObj = {}; 13 14 /** 15 * 构造函数 16 * @param option 17 * @constructor 18 */ 19 function AutoComplete(option) { 20 //需要实现自动完成功能的页面控件ID 21 this.controlId = option.controlId; 22 23 //匹配结果div的id 24 this.resultDivId = option.resultDivId; 25 26 //当前选中的项索引,第一项索引为0 27 this.index = -1; 28 29 //静态数据集 30 this.datas = option.datas; 31 32 //动态获取的数据集 33 this.dynamicDatas = null; 34 35 //服务器端地址 36 this.serverUrl = option.serverUrl; 37 38 //匹配结果集合 39 this.resultDatas = null; 40 41 //ajax请求数据 42 this.ajaxRequestData =http://www.mamicode.com/ option.ajaxRequestData; 43 44 //主要用在一个后台页面处理多个前端自动完成请求的情况,根据此字段调用具体的后台方法 45 this.actionName = option.actionName; 46 47 //是否可以循环选择 48 this.circleChoose = option.circleChoose || "true"; 49 50 //是否从服务器端获取数据 51 this.serverEnabled = option.serverEnabled || "false"; 52 53 //是否使用静态数据 54 //一般情况下,自动完成都是获取动态数据的,开启这个标志后,在获取动态数据失败的情况下会使用静态数据,默认为false 55 this.useStaticDatas = option.useStaticDatas||"false"; 56 57 //驱动函数 58 this.drivenFuc = null; 59 60 //自定义数据获取方法 61 this.getCompleteDatas = function (){ 62 if( typeof option.getCompleteDatas === ‘function‘ ){ 63 return option.getCompleteDatas(); 64 } 65 else{ 66 return null; 67 } 68 69 }; 70 71 72 //私有变量,封装后面常用的4个变量 73 //var commonObj = {}; 74 75 //通过匿名函数来构造一个类似面向对象语言中的只读属性 76 //初始化commonObj变量 77 //注意:匿名函数中的this指向windows对象,这里需要将AutoComplete对象的引用赋值给that 78 (function(that){ 79 commonObj = { 80 control : document.getElementById(that.controlId), 81 results : document.getElementById(that.resultDivId), 82 jControl : $(document.getElementById(that.controlId)), 83 jResults : $(document.getElementById(that.resultDivId)) 84 }; 85 })(this); 86 87 //只读属性 88 /*this.getCommonObj = function(){ 89 return commonObj; 90 }*/ 91 92 } 93 94 /** 95 * 原型方法,除了init方法和构造函数外,其他方法均需要私有化,待完善... 96 */ 97 AutoComplete.prototype = { 98 99 //指定构造函数100 constructor: AutoComplete,101 102 //获取事件对象103 getEvent: function() {104 return window.event || arguments[0]; //event ? event : window.event;105 },106 107 //获取事件源108 getTarget: function(event) {109 return event.target || event.srcElement;110 },111 112 /**113 * 计算div的偏移量114 * @param obj115 * @returns {{left: (Number|number), top: (Number|number)}}116 */117 getOffset: function(obj) {118 var x = obj.offsetLeft || 0;119 var y = obj.offsetTop || 0;120 var temp = obj;121 while (temp.offsetParent) {122 temp = temp.offsetParent;123 x += temp.offsetLeft;124 y += temp.offsetTop;125 }126 //alert("x:"+x+" y:"+y);127 return { left: x, top: y };128 },129 130 /**131 * 将tagetDiv定位到sourceDiv下方,与sourceDic左对齐,宽度一致132 * @param sourceDiv133 * @param targetDiv134 */135 positionDiv: function(sourceDiv, targetDiv) {136 var obj = document.getElementById(sourceDiv);137 var xy = this.getOffset(obj);138 $("#" + targetDiv).css("left", xy.left);139 $("#" + targetDiv).css("width", $("#" + sourceDiv).outerWidth());140 $("#" + targetDiv).css("top", (xy.top + $("#" + sourceDiv).outerHeight()));141 142 },143 144 init: function() {145 var control = document.getElementById(this.controlId);146 var results = document.getElementById(this.resultDivId);147 var jControl = $(control);148 var jResults = $(results);149 var autoThisObj = this;150 151 document.onclick = function(event) {152 //$("#"+resultDivId).hide();153 var target = autoThisObj.getTarget(autoThisObj.getEvent(event));154 //alert(target.id);155 if (target.id == autoThisObj.controlId) {156 return false;157 }158 autoThisObj.clearResults();159 }160 161 //兼容ie(ie浏览器下,当按下up与down键时,输入框会失去焦点,导致up与down键不起作用)162 jResults.bind("keydown", function(event) {163 jControl.keydown();164 return false;165 });166 167 168 //给指定控件绑定keyup事件169 $("#" + autoThisObj.controlId).bind("keyup", function(event) {170 var e = autoThisObj.getEvent(event);171 var keyCode = e.keyCode;172 if ((keyCode == ‘40‘ || keyCode == ‘38‘ || keyCode == ‘37‘ || keyCode == ‘39‘ || keyCode == ‘13‘ || keyCode == ‘9‘)) {173 return false;174 }175 176 autoThisObj.index = -1;177 results.scrollTop = 0;178 179 var keyword = $.trim(jControl.val());180 if (keyword.length == 0) {181 //jResults.hide();182 autoThisObj.clearResults();183 return;184 }185 186 //获取动态数据集,自定义函数的优先级最高187 var autoDatas = autoThisObj.getCompleteDatas();//调用自定义数据获取函数188 if( (autoDatas instanceof Array) && (autoDatas.length > 0) ){ 189 autoThisObj.dynamicDatas = autoDatas;190 }191 else if(autoThisObj.serverEnabled=="true"){ //服务器端获取数据192 autoThisObj.getAjaxDatas(); 193 }194 195 //196 if(autoThisObj.dynamicDatas!=null){197 autoThisObj.generateHtml(autoThisObj.dynamicDatas);198 }199 else if(autoThisObj.useStaticDatas=="true" && autoThisObj.datas.length>0){200 autoThisObj.generateHtml(autoThisObj.datas);201 } 261 }); //end keyup()262 263 this.navigate();264 }, // end init()265 266 /**267 * 定义 up与down 按键功能268 * @param event269 * @param objectId270 * @returns {boolean}271 */272 navigate: function(event) {273 274 var control = document.getElementById(this.controlId);275 var results = document.getElementById(this.resultDivId);276 var jControl = $(control);277 var jResults = $(results);278 279 var autoThisObj = this;280 281 this.keyDownBind(jControl);282 283 }, // end navigate()284 285 /**286 * 给指定jquery元素绑定keydown事件,使其可以进行匹配项的选择287 */288 keyDownBind: function(jObject) {289 var control = document.getElementById(this.controlId);290 var results = document.getElementById(this.resultDivId);291 var jControl = $(control);292 var jResults = $(results);293 var autoThisObj = this;294 jObject.keydown(function(event) {295 var e = autoThisObj.getEvent(event);296 var key = e.keyCode;297 if (i == "" || !i)298 i = -1;299 else300 i = parseFloat(i);301 302 var itemCount = results.childNodes.length;303 304 if (key == ‘40‘) //Down305 {306 307 for (var i = 0, len = itemCount; i < len; i++) {308 results.childNodes[i].className = "item"; //重置309 }310 311 autoThisObj.index++;312 313 if (autoThisObj.index > itemCount - 1) {314 if (autoThisObj.circleChoose == "true") {315 autoThisObj.index = 0;316 jResults.scrollTop(0);317 }318 else {319 autoThisObj.index = itemCount - 1;320 }321 }322 323 try {324 results.childNodes[autoThisObj.index].className = "item chooseItem";325 results.childNodes[autoThisObj.index - 1].className = "item";326 }327 catch (e) {328 329 }330 331 //以下两个判断语句用来将当前选中项置于div的可视范围内332 if (($(results.childNodes[autoThisObj.index]).height() + 4) * (autoThisObj.index + 1) > $(results).scrollTop() + parseInt(results.style.height)) {333 $(results).scrollTop(($(results.childNodes[autoThisObj.index]).height() + 4) * (autoThisObj.index + 1) - parseInt(results.style.height)); 334 }335 if (($(results.childNodes[autoThisObj.index]).height() + 4) * (autoThisObj.index) < $(results).scrollTop()) {336 $(results).scrollTop(($(results.childNodes[autoThisObj.index]).height() + 4) * (autoThisObj.index)); 337 }338 }339 else if (key == ‘38‘) //UP340 {341 for (var i = 0, len = itemCount; i < len; i++) {342 results.childNodes[i].className = "item"; //重置343 }344 345 autoThisObj.index--;346 if (autoThisObj.index < 0) {347 autoThisObj.index = 0;348 if (autoThisObj.circleChoose == "true") {349 autoThisObj.index = itemCount - 1;350 results.scrollTop = results.scrollHeight;351 }352 else {353 autoThisObj.index = 0;354 }355 }356 357 try {358 results.childNodes[autoThisObj.index].className = "item chooseItem";359 results.childNodes[autoThisObj.index + 1].className = "item";360 }361 catch (e) {362 363 }364 365 //以下两个判断语句用来将当前选中项置于div的可视范围内366 if (($(results.childNodes[autoThisObj.index]).height() + 4) * (autoThisObj.index + 1) > $(results).scrollTop() + parseInt(results.style.height)) {367 $(results).scrollTop(($(results.childNodes[autoThisObj.index]).height() + 4) * (autoThisObj.index + 1) - parseInt(results.style.height)); 368 }369 if (($(results.childNodes[autoThisObj.index]).height() + 4) * (autoThisObj.index) < $(results).scrollTop()) {370 $(results).scrollTop(($(results.childNodes[autoThisObj.index]).height() + 4) * (autoThisObj.index)); 371 }372 }373 else if (key == ‘13‘ || key == ‘9‘) // enter/tab374 {375 if (autoThisObj.index == -1)376 autoThisObj.index = 0;377 378 control.value =http://www.mamicode.com/ results.childNodes[autoThisObj.index].innerHTML;379 380 autoThisObj.clearResults();381 return false;382 }383 else {384 return;385 }386 }); // end keydown387 },388 389 /**390 * ajax方式获取匹配结果集391 */392 getAjaxDatas:function(){393 var autoThisObj = this;394 $.ajax({395 url: this.serverUrl,396 data: this.ajaxRequestData,397 type: "POST",398 success: function(returnValue) {399 if((returnValue instanceof Array)&&(returnValue.length > 0)){400 autoThisObj.dynamicDatas = returnValue;401 }402 else{403 autoThisObj.dynamicDatas = null;404 }405 } //end success()406 }); //end ajax()407 },408 409 /**410 * 获取数据后生成html,并绑定基本事件411 */412 generateHtml:function(datas){413 414 //var commonObj = this.getCommonObj();415 var autoThisObj = this;416 417 var length = datas.length;418 var htmlStr = "";419 420 if (length > 0) {421 422 for (var i = 0; i < length; i++) {423 htmlStr += "<div class=‘item‘>" + datas[i] + "</div>";424 }425 426 //htmlStr = "<div class=‘resultCss‘ id=‘"+ autoThisObj.resultDivId +"‘>" + htmlStr + "</div>";427 428 commonObj.jResults.html(htmlStr).show();429 430 431 //计算单个item的高度432 var itemHeight = $(".item").first().outerHeight();433 434 if (length >= 10) {435 commonObj.jResults.height(10 * itemHeight);436 }437 else {438 commonObj.jResults.height(length * itemHeight);439 }440 441 //调整结果div的宽度并定位442 autoThisObj.positionDiv(autoThisObj.controlId, autoThisObj.resultDivId);443 444 //默认选中第一项445 autoThisObj.index = 0;446 commonObj.results.childNodes[autoThisObj.index].className = "item chooseItem";447 448 //给结果集中的每一项添加基本事件449 commonObj.jResults.find(".item").each(function() {450 //点击事件451 $(this).on("click", function() {452 commonObj.jControl.val($(this).html());453 autoThisObj.clearResults();454 });455 456 //mouseover事件457 $(this).mouseover(function() {458 autoThisObj.index = $(this).index();459 var results = document.getElementById(autoThisObj.controlId);460 var itemCount = document.getElementById(autoThisObj.resultDivId).childNodes.length;461 for (var i = 0, len = itemCount; i < len; i++) {462 document.getElementById(autoThisObj.resultDivId).childNodes[i].className = "item"; //重置463 }464 document.getElementById(autoThisObj.resultDivId).childNodes[autoThisObj.index].className = "item chooseItem";465 466 });467 468 });469 }470 else {471 autoThisObj.clearResults();472 }473 },474 475 /**476 * 清空结果div477 */478 clearResults: function() {479 var results = document.getElementById(this.resultDivId);480 var jResults = $(results);481 results.innerHTML = "";482 jResults.scrollTop(0);483 results.style.display = "none";484 jResults.css("height", "auto");485 this.dynamicDatas = null;486 },487 488 //重置结果集489 resetResults: function() {490 var results = document.getElementById(this.resultDivId);491 var jResults = $(results);492 jResults.scrollTop(0);493 results.style.display = "none";494 this.index = 0;495 496 var itemCount = results.childNodes.length;497 for (var i = 0, len = itemCount; i < len; i++) {498 results.childNodes[i].className = "item"; //重置499 }500 501 results.childNodes[this.index].className = "item chooseItem";502 }503 504 }505 506 //将AutoComplete暴露到全局范围507 window.AutoComplete = AutoComplete;508 })();

 使用方法示例:

 1 <html> 2 <head> 3     <meta http-equiv="Content-type" content="text/html; charset=utf-8"> 4     <title>autoComplete测试</title> 5     <style type="text/css"> 6     .item /*每一项的样式*/ 7     { 8         line-height:20px; 9         height:20px;10         padding: 2px;11         width:100%;12         overflow: hidden;13     }14     .chooseItem{  /*选中的当前项样式*/15      background-color: #008B8B;16         color:White;17         cursor: pointer;18         height:20px;19         padding: 2px;20         width:100%;21         line-height:20px;22     }23     .resultsCss{ /*匹配结果集容器样式*/24         position:absolute;25         overflow-y:auto; 26         overflow-x:hidden; 27         display:none;28         border:solid 1px gray; 29         background-color:#F0FFFF;30     }31     </style>32     <script type="text/javascript" src="jquery-1.7.2.min.js"></script>33     <script type="text/javascript" src="autoCompleteHome.js"></script>34     35     <body>36         <div>37             <label for="inpt">请输入:</label><input type="text" id="inpt" />38         </div>39         <div id="tipList" class="resultsCss">40         </div>41         <script type="text/javascript">42         //方式1:静态数据集43         var staticDatas = ["asd","axcv","qwerfd","dfghj","cvbnm","bbghty","ertgb","trefgc","cssdavb","abcdefg","trefgc","cssdavb","abcdefg"];44         var autoCompleteOption = {45                         controlId: "inpt",46                         resultDivId: "tipList",47                         circleChoose: "true",48                         serverEndbled: "false",49                         useStaticDatas:"true",50                         datas:staticDatas51                     };52             53         var auto = new AutoComplete(autoCompleteOption);54         auto.init();55 56         //方式2:自定义数据获取函数57         /*58         var autoCompleteOption = {59                         controlId: "inpt",60                         resultDivId: "tipList",61                         circleChoose: "true",62                         getCompleteDatas:function(){63                             var datas = null;64                             //enter your code to get the data65                             return datas;66                         }67                     };68             69         var auto = new AutoComplete(autoCompleteOption);70         auto.init();71         */72 73         //方式3:ajax获取数据74         /*75         var autoCompleteOption = {76                         controlId: "inpt",77                         resultDivId: "tipList",78                         circleChoose: "true",79                         resultDivId: "tipList",80                         ajaxRequestData:{},81                         serverUrl: "AutoCompleteHandler.ashx"82                     };83             84         var auto = new AutoComplete(autoCompleteOption);85         auto.init();86         */87         </script>88     </body>89 </head>90 </html>