首页 > 代码库 > 自己手写的自动完成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>
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。