搜索框键入提示并回显准确信息

类似百度这种,大家应该也都清楚这个东西

我提供一个网上大家都在用的一个方法,整理了一下分享出来。

 

1.文本框和设置一个div,class=parentCls ,  搜索框的class设置:class=“inputElem”   , 为文本框设置一个oninput的属性。


<div class="parentCls">
                    <input type="text" class="inputElem" id="inputName" name="name" value="${search}"
                           oninput="onChange(this.value)">
                    <input class="btn btn-dark" type="submit" value="搜索" style="margin-left: 15px;">
                    <input type="hidden" class="hiddenCls"/>
                </div>

 

在返回数据之前,我们先创建一个接受返回的json值的变量。

var resultData;

2.编写JS。

  1   /**
  2      * JS 模糊查询
  3      * @param 1.当前的input add targetCls
  4      * 2. 隐藏域里面统一增加同类名 叫 hiddenCls
  5      * 3. 在各个父级元素上 添加类名 parentCls
  6      */
  7     function AutoComplete(options) {
  8         this.config = {
  9             targetCls: '.inputElem',          // 输入框目标元素
 10             parentCls: '.parentCls',          // 父级类
 11             hiddenCls: '.hiddenCls',          // 隐藏域input
 12             searchForm: '.jqtransformdone',     //form表单
 13             hoverBg: 'hoverBg',             // 鼠标移上去的背景
 14             outBg: 'outBg',               // 鼠标移下拉的背景
 15             isSelectHide: true,                 // 点击下拉框 是否隐藏
 16             url: 'search',                    // url接口
 17             height: 0,                     // 默认为0 不设置的话 那么高度自适应
 18             manySelect: false,                 // 输入框是否多选 默认false 单选
 19             renderHTMLCallback: null,                  // keyup时 渲染数据后的回调函数
 20             callback: null,                  // 点击某一项 提供回调
 21             closedCallback: null                   // 点击输入框某一项x按钮时 回调函数
 22         };
 23 
 24         this.cache = {
 25             currentIndex: -1,
 26             oldIndex: -1,
 27             inputArrs: []                 // 多选时候 输入框值放到数组里面去
 28         };
 29         this.init(options);
 30     }
 31 
 32     AutoComplete.prototype = {
 33 
 34         constructor: AutoComplete,
 35         init: function (options) {
 36 
 37             this.config = $.extend(this.config, options || {});
 38             var self = this,
 39                 _config = self.config,
 40                 _cache = self.cache;
 41 
 42             // 鼠标点击输入框时候
 43             $(_config.targetCls).each(function (index, item) {
 44 
 45                 /*
 46                  *  禁止 ctrl+v 和 黏贴事件
 47                  */
 48                 $(item).unbind('paste');
 49                 $(item).bind('paste', function (e) {
 50                     e.preventDefault();
 51                     var target = e.target,
 52                         targetParent = $(target).closest(_config.parentCls);
 53                     $(this).val('');
 54                     $(_config.hiddenCls, targetParent) && $(_config.hiddenCls, targetParent).val('');
 55                 });
 56 
 57                 $(item).keyup(function (e) {
 58                     _cache.inputArrs = [];
 59                     var targetVal = $.trim($(this).val()),
 60                         keyCode = e.keyCode,
 61                         elemHeight = $(this).outerHeight(),
 62                         elemWidth = $(this).outerWidth();
 63 
 64                     // 如果输入框值为空的话 那么隐藏域的value清空掉
 65                     if (targetVal == '') {
 66                         var curParents = $(this).closest(_config.parentCls);
 67                         $(_config.hiddenCls, curParents).val('');
 68                     }
 69                     var targetParent = $(this).parent();
 70                     $(targetParent).css({'position': 'relative'});
 71 
 72                     if ($('.auto-tips', targetParent).length == 0) {
 73                         // 初始化时候 动态创建下拉框容器
 74                         $(targetParent).append($('<div class="auto-tips hidden"></div>'));
 75                         $('.auto-tips', targetParent).css({
 76                             'position': 'absolute',
 77                             'top': elemHeight,
 78                             'left': '0px',
 79                             'margin-left': '383px',
 80                             'z-index': 999,
 81                             'width': elemWidth,
 82                             'border': '1px solid #ccc'
 83                         });
 84                     }
 85 
 86 
 87                     var curIndex = self._keyCode(keyCode);
 88                     if (curIndex > -1) {
 89                         self._keyUpAndDown(targetVal, e, targetParent);
 90                     } else {
 91                         if (targetVal != '') {
 92                             self._doPostAction(targetVal, targetParent);
 93                         }
 94 
 95                     }
 96                 });
 97 
 98                 // 失去焦点时 如果没有点击 或者上下移时候 直接输入 那么当前输入框值情况 隐藏域值情况
 99                 $(item).blur(function (e) {
100                     var target = e.target,
101                         targetParent = $(target).closest(_config.parentCls);
102                     if ($(this).attr('up') || $(this).attr('down')) {
103                         return;
104                     } else {
105                         $(this).val('');
106                         $(_config.hiddenCls, targetParent).val('');
107                     }
108                 });
109 
110             });
111 
112             // 阻止form表单默认enter键提交
113             $(_config.searchForm).each(function (index, item) {
114                 $(item).keydown(function (e) {
115                     var keyCode = e.keyCode;
116                     if (keyCode == 13) {
117                         return false;
118                     }
119                 });
120             });
121 
122             // 点击文档
123             $(document).click(function (e) {
124                 e.stopPropagation();
125                 var target = e.target,
126                     tagParent = $(target).parent(),
127                     attr = $(target, tagParent).closest('.auto-tips');
128 
129                 var tagCls = _config.targetCls.replace(/^\./, '');
130 
131                 if (attr.length > 0 || $(target, tagParent).hasClass(tagCls)) {
132                     return;
133                 } else {
134                     $('.auto-tips').each(function (index, item) {
135                         !$(item, tagParent).hasClass('hidden') && $(item, tagParent).addClass('hidden');
136                     });
137 
138                 }
139             });
140 
141             var stylesheet = '.auto-tips { margin: 0 1px; list-style: none;height:auto !important;padding: 0px;position:absolute; border:1px solid #ccc; top:27px; left:0; z-index:999; width:100%;background:#fff !important;}' +
142                 '.auto-tips p {overflow: hidden;margin: 1px 0;padding: 5px 5px;text-align:left;color: #666;text-decoration: none;line-height: 23px;white-space: nowrap;cursor: pointer;zoom: 1;}' +
143                 '.auto-tips p img{ vertical-align:middle;float:left;}' +
144                 '.auto-tips p.hoverBg {background-color: #669cb6;color: #fff;cursor: pointer;}' +
145                 '.hidden {display:none;}';
146 
147             this._addStyleSheet(stylesheet);
148 
149         },
150         /**
151          * 键盘上下键操作
152          */
153         _keyUpAndDown: function (targetVal, e, targetParent) {
154             var self = this,
155                 _cache = self.cache,
156                 _config = self.config;
157 
158             // 如果请求成功后 返回了数据(根据元素的长度来判断) 执行以下操作
159             if ($('.auto-tips p', targetParent) && $('.auto-tips p', targetParent).length > 0) {
160 
161                 var plen = $('.auto-tips p', targetParent).length,
162                     keyCode = e.keyCode;
163                 _cache.oldIndex = _cache.currentIndex;
164 
165                 // 上移操作
166                 if (keyCode == 38) {
167                     if (_cache.currentIndex == -1) {
168                         _cache.currentIndex = plen - 1;
169                     } else {
170                         _cache.currentIndex = _cache.currentIndex - 1;
171                         if (_cache.currentIndex < 0) {
172                             _cache.currentIndex = plen - 1;
173                         }
174                     }
175                     if (_cache.currentIndex !== -1) {
176 
177                         !$('.auto-tips .p-index' + _cache.currentIndex, targetParent).hasClass(_config.hoverBg) &&
178                         $('.auto-tips .p-index' + _cache.currentIndex, targetParent).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
179                         var curAttr = $('.auto-tips .p-index' + _cache.currentIndex, targetParent).attr('data-html');
180 //                            embId = $('.auto-tips .p-index'+_cache.currentIndex,targetParent).attr('embId');
181 
182                         // 判断是否是多选操作 多选操作 暂留接口
183                         if (_config.manySelect) {
184                             _cache.inputArrs.push(curAttr);
185                             _cache.inputArrs = self._unique(_cache.inputArrs);
186                             self._manySelect(targetParent);
187                         } else {
188                             $(_config.targetCls, targetParent).val(curAttr);
189                             // 上移操作增加一个属性 当失去焦点时候 判断有没有这个属性
190                             if (!$(_config.targetCls, targetParent).attr('up')) {
191                                 $(_config.targetCls, targetParent).attr('up', 'true');
192                             }
193 
194                             self._createDiv(targetParent, curAttr);
195                             // hover
196                             self._hover(targetParent);
197                         }
198 
199                     }
200 
201                 } else if (keyCode == 40) { //下移操作
202                     if (_cache.currentIndex == plen - 1) {
203                         _cache.currentIndex = 0;
204                     } else {
205                         _cache.currentIndex++;
206                         if (_cache.currentIndex > plen - 1) {
207                             _cache.currentIndex = 0;
208                         }
209                     }
210                     if (_cache.currentIndex !== -1) {
211 
212                         !$('.auto-tips .p-index' + _cache.currentIndex, targetParent).hasClass(_config.hoverBg) &&
213                         $('.auto-tips .p-index' + _cache.currentIndex, targetParent).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
214                         var curAttr = $('.auto-tips .p-index' + _cache.currentIndex, targetParent).attr('data-html');
215 //                            embId = $('.auto-tips .p-index'+_cache.currentIndex,targetParent).attr('embId');
216 
217 
218                         // 判断是否是多选操作 多选操作 暂留接口
219                         if (_config.manySelect) {
220                             _cache.inputArrs.push(curAttr);
221                             _cache.inputArrs = self._unique(_cache.inputArrs);
222                             self._manySelect(targetParent);
223                         } else {
224                             $(_config.targetCls, targetParent).val(curAttr);
225 
226                             // 下移操作增加一个属性 当失去焦点时候 判断有没有这个属性
227                             if (!$(_config.targetCls, targetParent).attr('down')) {
228                                 $(_config.targetCls, targetParent).attr('down', 'true');
229                             }
230 
231                             var pCls = $(_config.targetCls, targetParent).closest(_config.parentCls);
232 //                            $(_config.hiddenCls,pCls).val(embId);
233                             self._createDiv(targetParent, curAttr);
234                             self._closed(targetParent);
235                             // hover
236                             self._hover(targetParent);
237                         }
238 
239                     }
240                 } else if (keyCode == 13) { //回车操作
241                     var curVal = $('.auto-tips .p-index' + _cache.oldIndex, targetParent).attr('data-html');
242                     $(_config.targetCls, targetParent).val(curVal);
243                     /*
244                      if(_config.isSelectHide) {
245                      !$(".auto-tips",targetParent).hasClass('hidden') && $(".auto-tips",targetParent).addClass('hidden');
246                      }
247                      */
248 
249                     _cache.currentIndex = -1;
250                     _cache.oldIndex = -1;
251 
252                 }
253             }
254         },
255         // 键码判断
256         _keyCode: function (code) {
257             var arrs = ['17', '18', '38', '40', '37', '39', '33', '34', '35', '46', '36', '13', '45', '44', '145', '19', '20', '9'];
258             for (var i = 0, ilen = arrs.length; i < ilen; i++) {
259                 if (code == arrs[i]) {
260                     return i;
261                 }
262             }
263             return -1;
264         },
265         _doPostAction: function (targetVal, targetParent) {
266 
267             var self = this,
268                 _cache = self.cache,
269                 _config = self.config,
270                 url = _config.url;
271 
272             // 假如返回的数据如下:
273             if (resultData != null) {
274                 var result = JSON.parse(resultData);
275                 if (result.length > 0) {
276                     var results = result;
277                     self._renderHTML(results, targetParent);
278                     self._executeClick(results, targetParent);
279                 } else {
280                     !$('.auto-tips', targetParent).hasClass('hidden') && $('.auto-tips', targetParent).addClass("hidden");
281                     $('.auto-tips', targetParent).html('');
282                 }
283             }
284         },
285 
286         /*
287          $.get(url+"?keyword="+targetVal+"&timestamp="+new Date().getTime(),function(data){
288          var ret = $.parseJSON(data.content),
289          results = ret.results;
290          if(results.length > 0) {
291          self._renderHTML(results,targetParent);
292          self._executeClick(results,targetParent);
293          }else {
294          !$('.auto-tips',targetParent).hasClass('hidden') && $('.auto-tips',targetParent).addClass("hidden");
295          $('.auto-tips',targetParent).html('');
296 
297          }
298          });*/
299         _renderHTML: function (ret, targetParent) {
300             var self = this,
301                 _config = self.config,
302                 _cache = self.cache,
303                 html = '';
304 
305             for (var i = 0, ilen = ret.length; i < ilen; i += 1) {
306                 html += '<p  data-html = "' + ret[i].appname + '" class="p-index' + i + '">' +
307                     '<span>' + ret[i].appname + '</span>' +
308                     '</p>';
309             }
310             // 渲染值到下拉框里面去
311             $('.auto-tips', targetParent).html(html);
312             $('.auto-tips', targetParent).hasClass('hidden') && $('.auto-tips', targetParent).removeClass('hidden');
313             $('.auto-tips p:last', targetParent).css({"border-bottom": 'none'});
314 
315 
316             // 出现滚动条 计算p的长度 * 一项p的高度 是否大于 设置的高度 如是的话 出现滚动条 反之
317             var plen = $('.auto-tips p', targetParent).length,
318                 pheight = $('.auto-tips p', targetParent).height();
319 
320             if (_config.height > 0) {
321                 if (plen * pheight > _config.height) {
322                     $('.auto-tips', targetParent).css({'height': _config.height, 'overflow': 'auto'});
323                 } else {
324                     $('.auto-tips', targetParent).css({'height': 'auto', 'overflow': 'auto'});
325                 }
326             }
327         }
328         ,
329         /**
330          * 当数据相同的时 点击对应的项时 返回数据
331          */
332         _executeClick: function (ret, targetParent) {
333             var self = this,
334                 _config = self.config,
335                 _cache = self.cache;
336             $('.auto-tips p', targetParent).unbind('click');
337             $('.auto-tips p', targetParent).bind('click', function (e) {
338                 var dataAttr = $(this).attr('data-html');
339 //                    embId = $(this).attr('embId');
340 
341                 // 判断是否多选
342                 if (_config.manySelect) {
343                     _cache.inputArrs.push(dataAttr);
344                     _cache.inputArrs = self._unique(_cache.inputArrs);
345                     self._manySelect(targetParent);
346                 } else {
347                     $(_config.targetCls, targetParent).val(dataAttr);
348                     var parentCls = $(_config.targetCls, targetParent).closest(_config.parentCls),
349                         hiddenCls = $(_config.hiddenCls, parentCls);
350 //                    $(hiddenCls).val(embId);
351                     self._createDiv(targetParent, dataAttr);
352 
353                     // hover
354                     self._hover(targetParent);
355 
356 //                    !$(_config.targetCls,targetParent).hasClass('hidden') && $(_config.targetCls,targetParent).addClass('hidden');
357                 }
358                 self._closed(targetParent);
359                 if (_config.isSelectHide) {
360                     !$('.auto-tips', targetParent).hasClass('hidden') && $('.auto-tips', targetParent).addClass('hidden');
361                 }
362                 _config.callback && $.isFunction(_config.callback) && _config.callback();
363             });
364 
365             // 鼠标移上效果
366             $('.auto-tips p', targetParent).hover(function (e) {
367                 !$(this, targetParent).hasClass(_config.hoverBg) &&
368                 $(this, targetParent).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
369             });
370         }
371         ,
372         _hover: function (targetParent) {
373             $('.create-input span', targetParent).hover(function () {
374                 $(this).css({"background": '#ccc', 'padding-left': '0px'});
375             }, function () {
376                 $(this).css({"background": ''});
377             });
378         }
379         ,
380         // 动态的创建div标签 遮住input输入框
381         _createDiv: function (targetParent, dataAttr) {
382             var self = this,
383                 _config = self.config;
384             var iscreate = $('.create-input', targetParent);
385 
386             // 确保只创建一次div
387             if (iscreate.length > 0) {
388                 $('.create-input', targetParent).remove();
389             }
390             $(_config.targetCls, targetParent).val(dataAttr);
391             $('.alink', targetParent).css({'float': 'left', 'background': 'none'});
392         }
393         ,
394         // X 关闭事件
395         _closed: function (targetParent) {
396             var self = this,
397                 _config = self.config;
398             /*
399              * 点击X 关闭按钮
400              * 判断当前输入框有没有up和down属性 有的话 删除掉 否则 什么都不做
401              */
402             $('.alink', targetParent).click(function () {
403                 $('.create-input', targetParent) && $('.create-input', targetParent).remove();
404                 $(_config.targetCls, targetParent) && $(_config.targetCls, targetParent).hasClass('hidden') &&
405                 $(_config.targetCls, targetParent).removeClass('hidden');
406                 $(_config.targetCls, targetParent).val('');
407                 //清空隐藏域的值
408                 var curParent = $(_config.targetCls, targetParent).closest(_config.parentCls);
409                 $(_config.hiddenCls, curParent).val('');
410 
411                 var targetInput = $(_config.targetCls, targetParent);
412                 if ($(targetInput).attr('up') || $(targetInput).attr('down')) {
413                     $(targetInput).attr('up') && $(targetInput).removeAttr('up');
414                     $(targetInput).attr('down') && $(targetInput).removeAttr('down');
415                 }
416                 _config.closedCallback && $.isFunction(_config.closedCallback) && _config.closedCallback();
417             });
418         }
419         ,
420         /*
421          * 数组去重复
422          */
423         _unique: function (arrs) {
424             var obj = {},
425                 newArrs = [];
426             for (var i = 0, ilen = arrs.length; i < ilen; i++) {
427                 if (obj[arrs[i]] != 1) {
428                     newArrs.push(arrs[i]);
429                     obj[arrs[i]] = 1;
430                 }
431             }
432             return newArrs;
433         }
434         ,
435         /*
436          * 输入框多选操作
437          */
438         _manySelect: function (targetParent) {
439             var self = this,
440                 _config = self.config,
441                 _cache = self.cache;
442             if (_cache.inputArrs.length > 0) {
443                 $(_config.targetCls, targetParent).val(_cache.inputArrs.join(','));
444             }
445         }
446         ,
447         /*
448          * 判断是否是string
449          */
450         _isString: function (str) {
451             return Object.prototype.toString.apply(str) === '[object String]';
452         }
453         ,
454         /*
455          * JS 动态添加css样式
456          */
457         _addStyleSheet: function (refWin, cssText, id) {
458 
459             var self = this;
460             if (self._isString(refWin)) {
461                 id = cssText;
462                 cssText = refWin;
463                 refWin = window;
464             }
465             refWin = $(refWin);
466             var doc = document;
467             var elem;
468 
469             if (id && (id = id.replace('#', ''))) {
470                 elem = $('#' + id, doc);
471             }
472 
473             // 仅添加一次,不重复添加
474             if (elem) {
475                 return;
476             }
477             //elem = $('<style></style>'); 不能这样创建 IE8有bug
478             elem = document.createElement("style");
479             // 先添加到 DOM 树中,再给 cssText 赋值,否则 css hack 会失效
480             $('head', doc).append(elem);
481 
482             if (elem.styleSheet) { // IE
483                 elem.styleSheet.cssText = cssText;
484             } else { // W3C
485                 elem.appendChild(doc.createTextNode(cssText));
486             }
487         }
488         ,
489         /*
490          * 销毁操作 释放内存
491          */
492         destory: function () {
493             var self = this,
494                 _config = self.config,
495                 _cache = self.cache;
496             _cache.ret = [];
497             _cache.currentIndex = 0;
498             _cache.oldIndex = 0;
499             _cache.inputArrs = [];
500             _config.targetCls = null;
501         }
502     };
503     // 初始化
504     $(function () {
505         var auto = new AutoComplete({});
506     });
507 </script>

 

 

73行-83行,我手动设置了下他的位置,让他加载生成到我的搜索框下面。正好对准。

 

3:编写ajax:

  如果监测到搜索框内容改变 就请求action

 function onChange(value) {
        var textValue = $("#inputName").val(); //文本框的值
        if ($.trim(textValue) == "") {  //判断文本框的值是否为空
            return;
        }

        $.ajax({
            dataType: "text",
            type: "POST",
            url: "/search", //请求地址
            data: {"search": textValue}, //附带参数
            success: function (result) {  //返回结果
                var result = JSON.parse(result);  //将一个json字符串转换成对象
                if (result.status == 1) { //判断返回值
                    resultData = result.data;  //将返回的json信息,赋值给我们上面定义好的变量resultData
                }
            }
        });
    }

 

4.返回:resutData:

将返回的resultData,传给我们上面编写的js里面。(在273行有体现

 

效果: 

 

 我的sql :

select 搜索词 from 表名 where 搜索词 like  CONCAT('','${搜索词}','%' ) GROUP BY 搜索词 LIMIT 5


我是以匹配以什么内容开头去查询的信息, limit 5 是控制显示条数。
posted @ 2017-02-22 22:21  Timesyys  阅读(1886)  评论(0编辑  收藏  举报