自动补全搜索实现

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

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

  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="#" class="db">java</a>
    </li>
    <li>
        <a href="#" class="db">javaWeb</a>
    </li>
    <li>
        <a href="#" class="db">javaScript</a>
    </li>
    <li>
        <a href="#" 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 = 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 = 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的原因导致无法直接给文本框赋值。待修改。

时间: 2024-08-11 09:44:04

自动补全搜索实现的相关文章

仿百度自动补全搜索框效果(*附有源码下载)

页面效果及代码,(源码在下面的下载链接) <html> <head> <title></title> <link rel="stylesheet" type="text/css" href="css/semantic.css"> <script type="text/javascript" src="jquery-autocomplete/jquery

利用redis完成自动补全搜索功能(二)

前面介绍了自动完成的大致思路,现在把搜索次数的功能也结合上去.我采用的是hash表来做的,当然也可以在生成分词的时候,另外一个有序集合来维护排序, 然后2个有序集合取交集即可.这里介绍hash的方式来实现. 产生分词 dist.php <?php require './redis.php'; //分词 $words = ['花讯','nba','nba直播','nba赛事','nba季后赛','nba录像','花讯品牌','花讯女装','花','n']; //利用管道 Cache::getIns

第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能

第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲-用Django实现搜索的自动补全功能 elasticsearch(搜索引擎)提供了自动补全接口 官方说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html 创建自动补全字段 自动补全需要用到一个字段名称为suggest类型为Completion类型的一个字段 所以我们需要用

上课笔记_使用DWR实现自动补全 类似百度搜索框的自动显示效果

使用DWR实现自动补全 自动补全:是指用户在文本框中输入前几个字母或汉字的时候,自动在存放数据的文件或数据库中将所有以这些字母或汉字开头的数据提示给用户供用户选择 在日常上网过程中,我们经常使用搜索引擎,当我们输入想要检索的关键字时,搜索引擎会提示我们相关的关键字 训练要点: 掌握使用DWR框架开发Ajax程序 使用MyEclipse 10.0 + MySql5.0 新建数据库:可以手动随便新建一个测试用的 DROP TABLE IF EXISTS `books`; CREATE TABLE `

【Android】实现搜索的自动补全功能

[Android]实现搜索的自动补全功能 功能分类:特效 支持平台:Android 运行环境:Eclipse 开发语言:Java 开发工具:Eclipse 源码大小:815.56KB 下载地址:http://www.dwz.cn/x9bUV 源码简介 利用Sqlite模糊查询实现搜索框的自动补全效果(支持字母+汉字补全)欢迎各位小伙伴提供更好的实现思路 运行截图

四十七 Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能

elasticsearch(搜索引擎)提供了自动补全接口 官方说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html 1.创建搜索自动补全字段suggest 自动补全需要用到一个字段名称为suggest类型为Completion类型的一个字段 所以我们需要用将前面的elasticsearch-dsl操作elasticsearch(搜索引擎)增加sugg

一个模拟搜索自动补全的实例(超简单)

很早就像写一个模拟Google搜索栏自动补全的实例,那时候刚学点js,css也玩不转,即使网上有些demo,看起来也很费力.写了两次只是勉强能出来待筛选项,不能自由选择.这两天学了点jQuery的ajax,配合一点资料,自己成功实现了这个功能,jQuery的口号真是名副其实----The Write Less, Do More. CSS <style type="text/css" > .listbox{ position: relative; left: 10px; ma

知问前端——邮箱自动补全

本节课,我们通过自动补全source属性的function回调函数,来动态的设置我们的数据源,以达到可以实现邮箱补全功能. 数据源function 自动补全UI的source不但可以是数组,也可以是function回调函数,提供了自带的两个参数设置动态的数据源. $('#email').autocomplete({ source : function (request, response) { //获取用户输入的内容 alert(request.term); //可以获取你输入的值 //绑定数据

jquery autocomplete 自动补全

写在前面 autocomplete是jqueryUI里的一个插件 效果和说明可以访问这里,作用类似于搜索时的自动提示: 相信用过jQuery autocomplete 自动补全功能同学有不少,但是往往我们所对应的需求不同,有的仅仅是为了省事,敲两个字就有一堆可供选择的信息可供选择,但并不是所有需求都是这样的,我们还有这样的需求,敲两个字,将这个文字对应的实体绑定出来. 主要的参数 jQuery UI Autocomplete常用的参数有: Source:用于指定数据来源,类型为String.Ar