首页 Javascript 正文
208

An input with search dropdown

  • yiqingpeng
  • 2019-01-11
  • 0
  •  
<script>
    //parameter must be a Array.
    function Iterator(arr){
        this.data = arr;
        this.size = arr.length;
        this.position = 0;
    }
    Iterator.prototype.rewind = function(){
        this.position = 0;
        return this;
    };
    Iterator.prototype.getKey = function(){
        return this.position;
    };
    Iterator.prototype.current = function(){
        return this.data[this.position];
    };
    Iterator.prototype.next = function(){
        this.position = (this.position + 1) % this.size;
        return this;
    };
    Iterator.prototype.pre = function(){
        if (this.position < 0){
            this.position = 0;
        }
        this.position = (this.size + this.position - 1) % this.size;
        return this;
    };
    Iterator.prototype.valid = function (){
        return this.position < this.size && this.position >= 0;
    };
    
    //Polyfill of IE
    if (!Array.prototype.includes) {
        Array.prototype.includes =  function(searchElement, fromIndex) {
          if (this == null) {
            throw new TypeError('"this" is null or not defined');
          }
          var o = Object(this);
          var len = o.length >>> 0;
          if (len === 0) {
            return false;
          }
          var n = fromIndex | 0;
          var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
          while (k < len) {
            if (o[k] === searchElement) {
              return true;
            }
            k++;
          }
          return false;
        };
    }
    
    jQuery(function(){
        var $$ = jQuery, ENTER_KEY = 13, UP_KEY = 38, DOWN_KEY = 40;
        var blackListOfKey = [ENTER_KEY, UP_KEY, DOWN_KEY, 37, 39];
        var ModelFinder = {
            searchInput: $$('#search_input'),
            goBtn: $$('#search_btn'),
            optionsContainer: $$('#search_options'),
            lookupUrlByName: function (name){
                var url = '';
                name = String(name);
                this.optionsContainer.find('li').each(function(){
                    if ($$(this).text().toLowerCase() === name.toLowerCase()) {
                        url = $$(this).attr('data-url');
                    }
                });
                return url;
            },
            onGoBtnClick: function () {
                var url = this.lookupUrlByName($$.trim(this.searchInput.val()));
                if (!url) {
                    alert(this.searchInput.attr('data-tips'));
                    this.searchInput.focus();
                    return;
                }
                //alert(url);
                window.location.href = url;
            },
            hideOptionsContainer: function (){
                this.optionsContainer.hide().find('li').hide().removeClass('current');
            },
            onSelectedItem: function (item){
                item && this.searchInput.val(item.text());
            },
            filterMatchedItems: function (matchStr, matchBegin) {
                var that = this, found = false;
                if (matchStr) {
                    this.optionsContainer.find('li').each(function (){
                        if (matchBegin 
                            ? $$(this).text().toLowerCase().indexOf(matchStr.toLowerCase()) === 0 
                            : $$(this).text().toLowerCase().indexOf(matchStr.toLowerCase()) > -1) { 
                            $$(this).show();
                            found = true;
                        } else {
                            $$(this).hide();
                        }
                    });
                }
                
                if (found) {
                    this.optionsContainer.show().iterator = (function () {
                        var obj = new Iterator(that.optionsContainer.find('li:visible'));
                        var current = Iterator.prototype.current;
                        //Overwrite method 'current' of Iterator
                        obj.current = function (){
                            var curEle = current.apply(this, arguments);
                            curEle['scrollIntoView'] && curEle.scrollIntoView({behavior: 'smooth'});
                            that.optionsContainer.find('li').removeClass('current');
                            return $$(curEle).addClass('current');
                        };
                        obj.position = -1;
                        that.optionsContainer.find('li').removeClass('current');
                        return obj;
                    })();
                } else {
                    this.hideOptionsContainer();
                }
            }
        };
        
        ModelFinder.goBtn.on('click', function(){
            ModelFinder.onGoBtnClick();
        });
        
        ModelFinder.searchInput.on('keyup', debounce(function (e) {
            var value = $$.trim(this.value), keyCode = e.keyCode, DO_MATCH = 3;
            if (blackListOfKey.includes(keyCode) || value.length < DO_MATCH) {
                value.length < DO_MATCH && ModelFinder.hideOptionsContainer();
                return;
            }
            ModelFinder.filterMatchedItems(value);
        }, 100));
        
        ModelFinder.searchInput.on('keydown', function(e){
            var keyCode = e.keyCode;
            if (keyCode === ENTER_KEY || keyCode === UP_KEY || keyCode === DOWN_KEY) {
                return false;
            }
        });
        
        ModelFinder.searchInput.on('click', function(e){
            e.stopPropagation();
        });
        
        ModelFinder.optionsContainer.on('click', 'li', function (){
            ModelFinder.onSelectedItem($$(this));
            ModelFinder.hideOptionsContainer();
        });
        
        $$(document).on('click', function(){
            ModelFinder.hideOptionsContainer();
        });
        
        $$('#search_input_wrapper').on('keyup', function (e){
            var keyCode = e.keyCode;
            switch (keyCode) {
                case ENTER_KEY:
                    /*
                    if (ModelFinder.optionsContainer.iterator.valid()) {
                        ModelFinder.onSelectedItem(ModelFinder.optionsContainer.iterator.current());
                        ModelFinder.hideOptionsContainer();
                    }*/
                    ModelFinder.onGoBtnClick();
                    break;
                case UP_KEY:
                    if (ModelFinder.optionsContainer.is(':hidden')) return;
                    ModelFinder.onSelectedItem(ModelFinder.optionsContainer.iterator.pre().current());
                    break;
                case DOWN_KEY:
                    if (ModelFinder.optionsContainer.is(':hidden')) return;
                    ModelFinder.onSelectedItem(ModelFinder.optionsContainer.iterator.next().current());
                    break;
            }
            
        });
    });
    
    function debounce(fn, wait, immediate){
        var timeout;
        return function (){
            var context = this, args = arguments;
            var later = function (){
                timeout = null;
                if (!immediate) {
                    fn.apply(context, args);
                }
            };
            var callNow = immediate && !timeout;
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
            if (callNow) {
                fn.apply(context, args);
            }
        };
    }
</script>

<style>
    #search_input_wrapper{display:inline-block;position:relative;vertical-align:middle;}
    #search_options{display:none;list-style: none;position:absolute;left:0;top:38px;z-index:99;padding: 0;margin:0;overflow-y: auto;width:100%;max-height: 90px!important;background: #fff;}
    #search_options li{display:none;cursor:pointer;height:20px;line-height: 20px;text-align: left;padding-left: 5px;margin: 0;}
    #search_options li:hover{background: #C0DCF3;}
    #search_options li.current{background: #C0DCF3;}
</style>

<span>
    <div id="search_input_wrapper">
        <input id="search_input" data-tips="Please enter a name!" value=""/>
        <ul id="search_options">
            <li data-url="ace">Ace</li>
            <li data-url="boost">Boost</li>
        </ul>
    </div>
    <button id="search_btn" class="model-finder-btn btn btn-basic">Go</button>
</span>

正在加载评论...