zoukankan      html  css  js  c++  java
  • 自己手写的自动完成js类

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

    代码如下:(已更新,最新代码请参考:https://github.com/zjh-neverstop/AutoCompleteMulti

      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 = 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 obj 115 * @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 sourceDiv 133 * @param targetDiv 134 */ 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 event 269 * @param objectId 270 * @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 else 300 i = parseFloat(i); 301 302 var itemCount = results.childNodes.length; 303 304 if (key == '40') //Down 305 { 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') //UP 340 { 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/tab 374 { 375 if (autoThisObj.index == -1) 376 autoThisObj.index = 0; 377 378 control.value = results.childNodes[autoThisObj.index].innerHTML; 379 380 autoThisObj.clearResults(); 381 return false; 382 } 383 else { 384 return; 385 } 386 }); // end keydown 387 }, 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 * 清空结果div 477 */ 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:staticDatas
    51                     };
    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 data
    65                             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>
  • 相关阅读:
    python中的编码问题
    CVPR2018 Tutorial 之 Visual Recognition and Beyond
    hdu 1376 Octal Fractions
    hdu 1329 Hanoi Tower Troubles Again!
    hdu 1309 Loansome Car Buyer
    hdu 1333 Smith Numbers
    hdu 1288 Hat's Tea
    hdu 1284 钱币兑换问题
    hdu 1275 两车追及或相遇问题
    hdu 1270 小希的数表
  • 原文地址:https://www.cnblogs.com/neverstop/p/3831212.html
Copyright © 2011-2022 走看看