input模拟输入下拉框

    功能点:

    输入、下拉选择、根据输入内容模糊检索、键盘上下键选择

  实现思路:

    显示隐藏:

      input获取焦点显示,失去焦点隐藏

    下拉选择:

      以父元素为基准,通过绝对定位定位至input输入下方

    模糊检索:

      监听输入数据的变化,过滤符合要求的数据

    键盘上下选择:

      监听input的键盘事件,判断keycode值,再触发上下键时,动态计算滚动条滚动的距离

    控制事件触发频率,采用函数节流

  具体实现过程:

    节流函数:

 1 function throttle(func, wait, options) {//函数节流
 2         var context, args, result;
 3         var timeout = null;
 4         var previous = 0;
 5         if (!options) options = {};
 6         var later = function() {
 7             previous = options.leading === false ? 0 : new Date().getTime();
 8             timeout = null;
 9             result = func.apply(context, args);
10             if (!timeout) context = args = null;
11         };
12         return function() {
13             var now = new Date().getTime();
14             if (!previous && options.leading === false) previous = now;
15             var remaining = wait - (now - previous);
16             context = this;
17             args = arguments;
18             if (remaining <= 0 || remaining > wait) {
19                 if (timeout) {
20                     clearTimeout(timeout);
21                     timeout = null;
22                 }
23                 previous = now;
24                 result = func.apply(context, args);
25                 if (!timeout) context = args = null;
26             } else if (!timeout && options.trailing !== false) {
27                 timeout = setTimeout(later, remaining);
28             }
29             return result;
30         }
31     }

功能代码:

  1 xxx.directive('inputAndSelect', function ($timeout) {
  2     return {
  3       restrict: 'AE',
  4       replace: true,
  5       require: 'ngModel',
  6       scope: {
  7         'ngModel': '=',
  8         'data': '@',
  9         'callback': '&'
 10       },
 11       template: '<div class="select-box">' +
 12         ' <input type="text" ng-focus="inputOnFocus($event)" ng-blur="inputOnBlur()"' +
 13         '      ng-model="ngModel" style="z-index: 10;" class="form-control huowu-input"><span class="arrow-down" style="display:inline-block; 12px;height: 8px;right: 14px;' +
 14         '   border-left: 6px solid transparent;
' +
 15         '    border-right: 6px solid transparent;
' +
 16         '    border-top: 8px solid #818181;"></span>' +
 17         '   <div class="select-box-container" style="z-index: 999;background-color: #fff;" ng-show="showSelect">' +
 18         '     <div class="select-box-item" ng-click="selectInputItem(item)" ng-repeat="item in dataList">{{item}}</div></div>' +
 19         '</div>',
 20       link: function(scope, element, attrs) {
 21         //显示/隐藏下拉列表
 22         scope.showSelect = false;
 23         scope.dataList = [];
 24         scope.selectIndex = -1;
 25         var eleInput = element.find('input');
 26         eleInput.attr('id', attrs.id);
 27         //input获取焦点
 28         eleInput.unbind('focus').bind('focus',function() {
 29           scope.showSelect = true;
 30           scope.dataList = JSON.parse(scope.data);
 31           element.find('.select-box-container .select-box-item').removeClass('option-active');
 32           $timeout(function () {
 33             element.find('.select-box-container').scrollTop(0);
 34           }, 0);
 35           if (scope.ngModel) {
 36             scope.dataList = scope.dataList.filter(function(vv) {
 37               return vv.indexOf(scope.ngModel) !== -1;
 38             })
 39           }
 40           if(attrs.callback) {
 41             scope.$parent[attrs.callback]();
 42           }
 43         });
 44         //选择输入项
 45         scope.selectInputItem = function(item) {
 46           scope.ngModel = item;
 47           scope.showSelect = false;
 48         };
 49         
 50         //input失去焦点
 51         scope.inputOnBlur = function() {
 52           $timeout(function() {
 53             scope.selectIndex = -1;
 54             scope.showSelect = false;
 55           }, 200)
 56         };
 57         //监听输入数据的变化
 58         scope.$watch('ngModel', function(newVal) {
 59           if(!scope.data) return;
 60           var items = JSON.parse(scope.data);
 61           if (!newVal && typeof newVal === 'string') {
 62             scope.dataList = items;
 63           } else {
 64             scope.dataList = items.filter(function(vv) {
 65               return vv.indexOf(newVal) !== -1;
 66             })
 67           }
 68         });
 69         //监听键盘按下事件
 70         eleInput.unbind('keydown').bind('keydown', throttle(function(e) {
 71           //keycode 38 up 40 down
 72           var items = element.find('.select-box-container .select-box-item');
 73           var $container = element.find('.select-box-container');
 74           var keycode = e.keyCode;
 75           if (keycode === 40) {
 76             //按键向下
 77             scope.selectIndex++;
 78             scope.selectIndex = scope.selectIndex > scope.dataList.length - 1 ? 0 : scope.selectIndex;
 79           } else if (keycode === 38) {
 80             //按键向上
 81             scope.selectIndex--;
 82             scope.selectIndex = scope.selectIndex < 0 ? scope.dataList.length - 1 : scope.selectIndex;
 83           } else if (keycode === 13) {
 84             if (scope.selectIndex !== -1) {
 85               scope.ngModel = scope.dataList[scope.selectIndex];
 86               scope.showSelect = false;
 87             }
 88             element.find('input').blur();
 89           }else {
 90             return;
 91           }
 92           items.removeClass('option-active');
 93           $(items[scope.selectIndex]).addClass('option-active');
 94           if(scope.selectIndex === 0) {
 95             $container.scrollTop(0);
 96           }
 97           $container.scrollTop(scope.selectIndex*25);
 98         }, 50));
 99       }
100     }
101   })

   效果图:

  

原文地址:https://www.cnblogs.com/gerry2019/p/10448168.html