首页 > 代码库 > 自动补全搜索实现

自动补全搜索实现

目前大多数搜索框都已实现自动补全功能,自己也私底下实现了一个简易版本,

在此总结过程中的一些要点:

  1,侦听文本框的value值改变,注意在Ie8及其之前版本的onpropertychange和Ie9的oninput事件与

  W3C下的oninput事件的异同;

  2,ajax请求数据;

  3,自动补全框的定位;

  4,上下键导航以及鼠标导航

 

在此附上源码:

  

        .auto-ul{            list-style: none;            padding: 0;            margin: 0;        }        .auto-ul li{            margin: 0;            padding:5px;        }        .auto-ul a{            text-decoration: none;            color: black;        }        .w{            background: #cecece;            cursor: default;        }        input{            border: 1px solid #c0c0c0;        }
<div class="w250 h200 bgf0 auto tc pt15">        <div>            <form>                <label for="t">username:&nbsp;</label>                <input type="text" id="t" autocomplete="false" class="p5 w150 lh22">            </form>        </div> </div>
        items.txt文件    <ul>    <li>        <a href="http://www.mamicode.com/#" class="db">java</a>    </li>    <li>        <a href="http://www.mamicode.com/#" class="db">javaWeb</a>    </li>    <li>        <a href="http://www.mamicode.com/#" class="db">javaScript</a>    </li>    <li>        <a href="http://www.mamicode.com/#" class="db">javaScript & CSS</a>    </li></ul>
     function $(m){            return document.getElementById(m)        }        function createBox(){            var div = document.createElement(‘div‘),w;            w = $(‘t‘).offsetWidth;            div.id = ‘box‘;            div.style.cssText = ‘position:absolute;width:‘+(w-2)+‘px;border:1px solid #cecece;display:none;‘;            div.innerHTML = ‘<ul class="auto-ul" id="autobox-ul"></ul>‘            return div;        }        function showBox(d,boxLocation){            d.style.display = ‘‘;            d.style.left = boxLocation.left + ‘px‘;            d.style.top = boxLocation.top + ‘px‘;        }        function hideBox(d){            d.style.display = ‘none‘;            d.getElementsByTagName(‘ul‘)[0].innerHTML = ‘‘;        }        //创建xhr        function createXHR(){            if(‘XMLHttpRequest‘ in window){                createXHR = function(){                    return new XMLHttpRequest();                }            }else{                var i= 0,len, fns = [function(){return new ActiveXObject(‘Microsoft.XMLHTTP‘)},function(){return new ActiveXObject(‘Msxml2.XMLHTTP‘)},                    function(){return new ActiveXObject(‘Msxml2.XMLHTTP.3.0‘)},function(){return new ActiveXObject(‘Msxml2.XMLHTTP.6.0‘)}];                for(len = fns.length;i<len;i++){                    try{                        fns[i]();                        createXHR = fns[i];                        break;                    }catch (e){                    }                }            }            return createXHR();        }        // ajax实现        function ajaxInit(ajaxData){            var xhr = createXHR(),get_data,isLoaded = false,                    map = {                        ‘html‘: ‘text‘,                        ‘arraybuffer‘: ‘arraybuffer‘,                        ‘blob‘: ‘blob‘,                        ‘document‘: ‘document‘,                        ‘json‘: ‘text‘                    };            ajaxData.onBefore = ajaxData.onBefore || function(){};            ajaxData.onSuccess = ajaxData.onSuccess || function(){};            ajaxData.onFailure = ajaxData.onFailure || function(){};            ajaxData.onComplete = ajaxData.onComplete || function(){};            ajaxData.timeout = ajaxData.timeout || 5000;            ajaxData.type = ajaxData.type || ‘post‘;            /**             * ‘text‘:返回类型为字符串,这是默认值。                ‘arraybuffer‘:返回类型为ArrayBuffer。                ‘blob‘:返回类型为Blob。                ‘document‘:返回类型为Document,用于xml。                ‘json‘:返回类型为JSON object,支持JSON的浏览器(Firefox>9,chrome>30),                就会自动对返回数据调用JSON.parse() 方法。也就是说,你从xhr.response属性                (注意,不是xhr.responseText属性)得到的不是文本,而是一个JSON对象。             */            if(xhr.responseType)                   xhr.responseType = ajaxData.responseType in map ? map[ajaxData.responseType] : ‘text‘;            ajaxData.onBefore();            xhr.open(ajaxData.type,ajaxData.url,true);            xhr.onreadystatechange = function(){                if(xhr.readyState == 4 && !isLoaded){                    // 判断响应成功的几点:                    // 1,如果是访问本地文件,请求成功但不会获得响应码                    // 2,IE(通过ActiveXObject创建的xhr对象)会将204设置为1223                    // 3, opera会将204设置为0                    if(!xhr.status && location.protocol == ‘file:‘                            || xhr.status == 1223                            || xhr.status == 0 || xhr.status >= 200 && xhr.status < 300                            || xhr.status == 304){                        if(ajaxData.responseType.toLowerCase() == ‘json‘){                            get_data = ‘JSON‘ in window ? JSON.parse(xhr.responseText) :                                    new Function(‘return ‘ + xhr.responseText + ";");                        }else if(ajaxData.responseType.toLowerCase() == ‘html‘){                            get_data = xhr.responseText;                        }else if(xhr.responseType.toLowerCase() == ‘document‘){                            get_data = xhr.responseXML;                        }else{                            get_data = xhr.response;                        }                        ajaxData.onSuccess(get_data);                    }else{                        ajaxData.onFailure();                    }                    ajaxData.onComplete();                    xhr = null;                }            }            setTimeout(function(){                isLoaded = true;            },ajaxData.timeout);            if(ajaxData.type.toLowerCase() == ‘get‘){                xhr.setRequestHeader(‘X-Request-With‘,‘XMLHttpRequest‘);                xhr.send(null);            }else if(ajaxData.type.toLowerCase() == ‘post‘ && ajaxData.data){                xhr.setRequestHeader(‘X-Request-With‘,‘XMLHttpRequest‘);                xhr.setRequestHeader(‘content-type‘,‘application/x-www-form-urlencoded‘);                xhr.send(ajaxData.data);            }            return xhr;        }        function addEvent(el,type,fn){            if(window.addEventListener){                el.addEventListener(type,fn,false)            }else{                el.attachEvent(‘on‘+type,function(){                    var e = window.event;                    e.preventDefault = function(){                        e.returnValue = false;                    };                    e.stopPropagation = function(){                        e.cancelBubble = true;                    }                    fn.call(el,e);                })            }        }        //给文本框绑定事件        function bindEvent(t,fn){            var input = t;            //对输入框绑定事件            if(input.addEventListener){                input.addEventListener(‘input‘,fn,false);            }else{                input.attachEvent(‘onpropertychange‘,function(){                    var e = window.event;                    if(e.propertyName == ‘value‘){                         fn();                    }                });            }            if(window.VBArray && window.addEventListener && !window.WebSocket){                input.addEventListener(‘keyup‘,function(e){                    var code = e.keycode || e.charcode;                    if(code==8 || code==46){                        fn();                    }                },false) ;                input.oncut=function(){fn()};            }            //对按键事件侦听            addEvent(input,‘keydown‘,function(e){                var l,ol = -1,nl;                if(e.keyCode == 40 || e.keyCode == 38){                    e.preventDefault();                    l = $(‘autobox-ul‘).getElementsByTagName(‘li‘);                    for(var i=0,len=l.length;i<len;i++){                        if(l[i].className == ‘w‘){                            ol = i;  //保存当前选定的选项                        }                        l[i].className = ‘‘;                    }                    if(e.keyCode == 40 || e.charCode == 40){ //下箭头                        ol++;                        if(ol <= len-1){                            l[ol].className = ‘w‘;                            nl = l[ol];                        }else{                            l[0].className = ‘w‘;                            nl = l[0];                        }                    }else if(e.keyCode == 38 || e.charCode ==38){ //上箭头                        ol--;                        if(ol >= 0){                            l[ol].className = ‘w‘;                            nl = l[ol];                        }else{                            l[l.length-1].className = ‘w‘;                            nl = l[l.length-1];                        }                    }                    this.value = http://www.mamicode.com/nl.getElementsByTagName(‘a‘)[0].innerHTML;                    nl.className = ‘w‘;                }            });            addEvent($(‘box‘),‘mousemove‘,function(e){                var t = e.target || e.srcElement,                        l = $(‘autobox-ul‘).getElementsByTagName(‘li‘);                e.preventDefault();                for(var i= 0,len=l.length;i<len;i++){                    l[i].className = ‘‘;                }                if(t.tagName.toLowerCase() == ‘a‘){                    t.parentNode.className = ‘w‘;                    input.value = t.innerHTML;                }            })            //若输入框失去焦点,则隐藏补全框            addEvent(input,‘blur‘,function(){                hideBox($(‘box‘))            })        }        (function(){            var t = $(‘t‘),div,boxLocation,ul;            div = createBox();            boxLocation = {                left: t.getBoundingClientRect().left + parseInt(document.documentElement.scrollLeft || document.body.scrollLeft || 0)                    - parseInt(document.documentElement.clientLeft || document.body.clientLeft || 0),                top: t.getBoundingClientRect().top + parseInt(document.documentElement.scrollTop || document.body.scrollTop || 0)                        - parseInt(document.documentElement.clientTop || document.body.clientTop || 0) +                        parseInt(t.offsetHeight)            };            document.body.appendChild(div);            ul = $(‘autobox-ul‘);            bindEvent(t,function(){                var value =http://www.mamicode.com/ t.value;                ajaxInit({                    type: ‘get‘,                    timeout: 3000,                    url: ‘./items.txt‘,                    responseType: ‘html‘,                    onSuccess: function(data){                        var d = document.createElement(‘div‘);                        d.innerHTML = data;                        d = d.getElementsByTagName(‘ul‘)[0];                        ul.innerHTML = d.innerHTML;                        showBox(div,boxLocation)                    }                })            })        })()

  经测试,IE8及其之前版本有bug,主要是因为onpropertychange的原因导致无法直接给文本框赋值。待修改。

自动补全搜索实现