自己手写的自动完成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 = 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>

自己手写的自动完成js类

时间: 2024-08-08 05:38:59

自己手写的自动完成js类的相关文章

手写代码自动实现自动布局,即Auto Layout的使用

手写代码自动实现自动布局,即Auto Layout的使用,有需要的朋友可以参考下. 这里要注意几点: 对子视图的约束,若是基于父视图,要通过父视图去添加约束. 对子视图进行自动布局调整,首先对UIView的一个属性设置,这是因为如果我们用Interface Builder,勾选Ues Autolayout,这时autoresizingMask就会被Auto Layout 取代,在手写代码时,我们就需要手动控制,代码如下 [_shadow setTranslatesAutoresizingMask

一套手写ajax加一般处理程序的增删查改

倾述下感受:8天16次驳回.这个惨不忍睹. 好了不说了,说多了都是泪. 直接上代码 : 这个里面的字段我是用动软生成的,感觉自己手写哪些字段太浪费时间了,说多了都是泪 ajax.model层的代码: using System; namespace Ajax.Model { /// <summary> /// SM_Class:实体类(属性说明自动提取数据库字段的描述信息) /// </summary> [Serializable] public partial class SM_C

Hibernate自动生成DO手写DAO的注意事项

自动生成DO,手写DAO: Myeclipse添加Hibernate支持:注意别勾abstract 生成DO:进入MyEclipse的Database Explorer右键要操作的表(注意一定要有主键)点击Hibernate Reverse,其中Id选择native. 手写DAO: Configuration con = new Configuration().configure();//构造核心类 SessionFactory factory = con.buildSessionFactory

jQuery手写几个常见的滑动下拉菜单 分分秒秒学习JS

一般的企业网站再我们再实际工作中,有些特效,用jQuery来做,显得极其简单,除非一些大的公司,需要封装自己的类. 今天,我们讲解jQuery入门知识,来写几个简单jQuery滑动下拉菜单.感受一下jQuery的简单快速的神奇之处. 学完本章,可以书写最常见的下拉菜单写法. 案例1 效果如图所示: 在书写这个滑动的下拉菜单的时候,我们首先来认识下jQuery里面的滑动方法 :slideToggle() slideToggle(执行时间,运动方式,返回函数) 执行时间: 常用的是 "slow&qu

手写js面向对象选项卡插件

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>无缝滚动</title>    <style type="text/css">        body,ul{margin: 0;padding: 0;}        li{list-style: none;}  

vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件

vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件/库 一提到移动端的下拉刷新上拉翻页,你可能就会想到iScroll插件,没错iScroll是一个高性能,资源占用少,无依赖,多平台的javascript滚动插件.iScroll不仅仅是 滚动.它可以处理任何需要与用户进行移动交互的元素.在你的项目中包含仅仅4kb大小的iScroll,你的项目便拥有了滚动,缩放,平移,无限滚动,视差滚动,旋转功能.iScroll的强大毋庸置疑,本人也非常欢迎大家使用iScr

不用写软件,纯JS 实现QQ空间自动点赞

这里分享一个自己写的点赞JS,已实现了右边图片点赞,有兴趣的朋友可以加上去玩玩.打开浏览器的开发者模式运行就可以看到效果了 function ilike() { var b = document.getElementById("fhp_like"); var c = b.childNodes[1]; console.log(c.childNodes.length); for (var i = 0; i < c.childNodes.length; i++) { var a1 =

js手写&#39;Promise&#39;

/* * pending:初始化成功 * fulfilled:成功 * rejected:失败 * */ function Promise(executor) {// 执行器 this.status = 'pending'; this.value = undefined; this.reason = undefined; this.fulfilledCallback = []; this.rejectCallback = []; let resolve = (value)=>{ if(this.

关于java写一个单例类(面试手写题)

package com.shundong.javacore; /** * java写一个简单的单例类 * @author shundong * */ class Singleton { //使用一个类变量来缓存曾经创建的实例 private static Singleton instance; //对构造进行隐藏(private) private Singleton(){} /** * 提供一个静态方法 * 该方法加入了自定义控制 保证只产生一个Singleton对象 * @return 返回S