zoukankan      html  css  js  c++  java
  • 头部布局,搜索验证和AJAX自动搜索提示,并封装成组件,提高代码复用性

    index.html 头部区结构和样式

    效果图

     静态样式

    index.html中的部分

        <!-- 头部 -->
        <div class="header">
            <div class="container">
                <!-- h1标签是为了搜索引擎优化,表示重要
                但是页面内不要出现太多 -->
                <h1 class="fl"><a href="#" class="header-logo text-hidden">慕淘网</a></h1>
                <div class="search fl">
                    <!-- 由于没有自己的搜索页,演示时设置为提交到淘宝,参考淘宝设置 -->
                    <form action="https://s.taobao.com/search">
                        <!-- 由于input是内联块,相当于display:inline-block
                        如果换行写,会造成空隙,空隙大小一般是默认字体的一半
                        可以不换行书写,但是可读性较差
                        都添加左浮动可以解决 -->
                        <!-- 设置name才能提交 -->
                        <input type="text" class="search-input fl" name="q" placeholder="灵魂美食一元抢" autocomplete="off">
                        <input type="submit" value="搜索" class="search-btn fl">
                    </form>
                    <ul class="search-list">
                        <li class="search-item text-ellipsis" title="111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111">111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111</li>
                        <li class="search-item text-ellipsis" title="222">222</li>
                        <li class="search-item text-ellipsis" title="333">333</li>
                    </ul>
                </div>
                <div class="header-cart fr"></div>
            </div>
        </div>

    common.css中新增搜索框组件公共样式

    /*搜索框组件 search*/
    .search{
        position: relative;
        width:679px;
        border:1px solid #cfd2d5;
    }
    .search-input{
        width:586px;
        height:40px;
        line-height:40px;
        background-color:#fff;
        border:none;
        padding:0 10px;
    }
    .search-btn{
        width:73px;
        height:40px;
        background-color:#07111b;
        color:#fff;
        line-height:40px;
        text-align: center;
        cursor:pointer;
        border:none;
    }
    .search-list{
        display: none;
        background-color:#fff;
        position: absolute;
        width:586px;
        top:100%;/*父容器的高度*/
        left:-1px;
        border:1px solid #cfd2d5;
        padding:0 10px;
    
    }
    .search-item{
        height:24px;
        line-height:24px;
    }

    index.css中新增header中独有的样式

    /*header*/
    .header{
        height:124px;
        background-color: #f3f5f7;
    }
    .header-logo{
        display: block;
        background:url(../img/header-logo.png) no-repeat;
        width:136px;
        height:48px;
        margin-top:36px;
        margin-left:15px;
    }
    .header .search{
        margin-top:36px;
        margin-left:144px;
    }

    引入search.js文件

    这里补充下几个文本框事件的触发条件的区别:

    change  文本框内容改变 + blur

    keypress  按键触发,如果鼠标不抬起连续按键,则连续触发

    keyup 按键释放触发,不管按什么键(包括上下箭头等无文字意义符号),而且鼠标粘贴过来的文本无法触发

    input 文本输入,跟change的区别是不需要 blur 即可触发;鼠标粘贴也可触发(兼容性不好:IE8以下不支持)

    综上所述,最理想的选择是 input,但有时为了兼容性,只能选择 keyup,并可以自己做一些约束改造


    查看淘宝搜索的form表单提交action

    //s.taobao.com/search

    自己在表单使用时参考淘宝需要在前面加上https:协议

    即:https://s.taobao.com/search

    查看淘宝搜索输入框的name属性

    name="q"

    查看淘宝提交时ajax请求的url地址

    1、打开网址,打开控制台,找到network,点击下面的JS

    2、可以先用绿色框的那个按钮将下面的内容清空一下,然后在输入框中写内容,下面Name的地方就会出来信息

    3、点击任意一个进去,就会出现右侧的Headers,里面的Request URL粘贴复制在浏览器地址栏中就可以看到了。

     

     


    添加搜索验证和获取数据功能:

    search.js

    (function($){
        "use strict";
    
        //验证
        var search=$(".search"),
            searchInput=search.find(".search-input"),
            searchBtn=search.find(".search-btn"),
            searchList=search.find(".search-list");
    
        searchBtn.on("click",function(){
            //submit按钮默认行为是提交表单,return false可以阻止默认行为
            //$.trim() 去掉字符串两边的空格,阻止无内容提交
            if($.trim(searchInput.val())==="") return false;
    
        });
    
        //自动完成
        searchInput.on("input",function(){
            var url = 'https://suggest.taobao.com/sug?code=utf-8&_ksTS=1484204931352_18291&callback=jsonp18292&k=1&area=c2c&bucketid=6&q='
             + encodeURIComponent($.trim(searchInput.val()));
    
            $.ajax({
                url:url,
                dataType:"jsonp",//jsonp用于跨域
                success:function(data){
                    console.log(data);
                },
                error:function(data){
                    console.log(error);
                }
            });
    
        });
    
    })(jQuery)

    由于jQuery.ajax返回的是jqXHR对象,它是浏览器原生XMLHttpRequest对象的一个超集,为了让回调函数名字统一,便于$.ajax中使用,jqXHR提供了.error(),.success(),.complete()

    由于版本升级,才有了相应的.fail(),.done(),.always()三个方法

    使用done(), fail(), always()是 为了避免代码嵌套在ajax里面,方便阅读

    因此$.ajax写法可以做如下修改,异步避免回调:

            // 异步避免回调
            $.ajax({
                url:url,
                timeout:1,//失败常见原因是超时,这里为了演示,将超时设置为1毫秒
                dataType:"jsonp"
            }).done(function(data){//成功执行
                console.log(data);
            }).fail(function(){//失败执行
                console.log("fail");
            }).always(function(){//总是执行
                console.log("always");
            });

     失败有很多种原因,其中超时是一个很常见的原因

    为了演示超时,设置timeout:1 (1毫秒)

     $.trim(searchInput.val()) 这边默认是使用的utf-8编码

    如果在页面为其他编码格式,如:gbk 时,可能会因为编码问题造成读取数据失败

    因此使用 encodeURIComponent( ) 来解决编码问题

    1、encodeURIComponent(URIstring ) 函数可把字符串作为 URI 组件进行编码,返回值是URIstring 的副本,其中的某些字符将被十六进制的转义序列进行替换。简单来说作用就是进行编码,能够被后台识别,后台开发语言都有相应的解码 api,这样就可以成功的返回数据。

    2、网页的编码会影响到发送请求时数据的编码,所以不一致时需要编码。

            var url = 'https://suggest.taobao.com/sug?code=utf-8&_ksTS=1484204931352_18291&callback=jsonp18292&k=1&area=c2c&bucketid=6&q='
             + encodeURIComponent($.trim(searchInput.val()));

    生成下拉层数据结构

    (function($){
        "use strict";
    
        //验证
        var search=$(".search"),
            searchInput=search.find(".search-input"),
            searchBtn=search.find(".search-btn"),
            searchList=search.find(".search-list");
    
        searchBtn.on("click",function(){
            //submit按钮默认行为是提交表单,return false可以阻止默认行为
            //$.trim() 去掉字符串两边的空格,阻止无内容提交
            if($.trim(searchInput.val())==="") return false;
    
        });
    
        //自动完成
        searchInput.on("input",function(){
            var url = 'https://suggest.taobao.com/sug?code=utf-8&_ksTS=1484204931352_18291&callback=jsonp18292&k=1&area=c2c&bucketid=6&q='
             + encodeURIComponent($.trim(searchInput.val()));
    
            // 异步避免回调
            $.ajax({
                url:url,
                dataType:"jsonp"
            }).done(function(data){//成功执行
                //console.log(data["result"]);
    
                var html="";
                var dataNum=data["result"].length;//实际数据量
                var maxNum=10;//最大显示数据量
                if(dataNum===0) searchList.hide().html("");
    
                for(var i=0;i<dataNum;i++){
                    if(i>=maxNum) break;
                    //console.log(data["result"][i][0]);
                    html+='<li class="search-item text-ellipsis" title="'+data["result"][i][0]+'">'+data["result"][i][0]+'</li>';
                }
                searchList.html(html).show();
    
            }).fail(function(){//失败执行
                searchList.hide().html("");
            }).always(function(){//总是执行
                console.log("always");
            });
    
        });
    
    })(jQuery)

    顺便将之前index.html中这部分注释掉

                    <ul class="search-list">
                        <!-- <li class="search-item text-ellipsis" title="111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111">111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111</li>
                        <li class="search-item text-ellipsis" title="222">222</li>
                        <li class="search-item text-ellipsis" title="333">333</li> -->
                    </ul>

    效果

    事件代理和显示隐藏下拉层

    (function($){
        "use strict";
    
        //验证
        var search=$(".search"),
            searchForm=search.find(".search-form"),
            searchInput=search.find(".search-input"),
            searchBtn=search.find(".search-btn"),
            searchList=search.find(".search-list");
    
        searchForm.on("submit",function(){
            //return false可以阻止默认行为,即阻止表单提交
            //$.trim() 去掉字符串两边的空格,阻止无内容提交
            if($.trim(searchInput.val())==="") return false;
    
        });
    
        //自动完成
        searchInput.on("input",function(){
            var url = 'https://suggest.taobao.com/sug?code=utf-8&_ksTS=1484204931352_18291&callback=jsonp18292&k=1&area=c2c&bucketid=6&q='
             + encodeURIComponent($.trim(searchInput.val()));
    
            // 异步避免回调
            $.ajax({
                url:url,
                dataType:"jsonp"
            }).done(function(data){//成功执行
                //console.log(data["result"]);
    
                var html="";
                var dataNum=data["result"].length;//实际数据量
                var maxNum=10;//最大显示数据量
                if(dataNum===0) searchList.hide().html("");
    
                for(var i=0;i<dataNum;i++){
                    if(i>=maxNum) break;
                    //console.log(data["result"][i][0]);
                    html+='<li class="search-item text-ellipsis" title="'+data["result"][i][0]+'">'+data["result"][i][0]+'</li>';
                }
                searchList.html(html).show();
    
            }).fail(function(){//失败执行
                searchList.hide().html("");
            }).always(function(){//总是执行
                console.log("always");
            });
    
        });
    
        //jquery的事件代理
        //事件绑定在父元素上,第一个参数是事件,第二个参数是被代理的子元素们,第三个参数是函数
        //函数里的$(this)指向的是被代理的子元素
        searchList.on("click",".search-item",function(){
            searchInput.val(removeHTML($(this).html()));
            searchForm.submit();
        });
    
        //显示隐藏下拉层
        // searchInput.on("focus",function(){
        //     searchList.show();
        // }).on("blur",function(){
        //     searchList.hide();
        // });
        //以上这种方法不可行,会导致点击列表项失效
        //因为blur事件与click事件冲突
        //因为在选项上按下鼠标时,已经触发了input的blur事件,导致列表隐藏;再出发列表项的点击时,列表已经被隐藏
        searchInput.on("focus",function(){
            searchList.show();
        }).on("click",function(){
            return false;//阻止点击时冒泡到document
        });
        $(document).on("click",function(){
            searchList.hide();
        });
    
    
        //去掉下拉列表项目的html标签,不然点击后会显示在搜索框中
        function removeHTML(str){
            // 示例:<input type="text" value=">" name='username' />
            // 1、标签中的属性使用的引号 可能是双引号,也可能是单引号,所以匹配引号外面的内容使用^取反,双引号,单引号和>不能获取,其他都是可以获取的。
            // 2、匹配引号里面的内容,不能匹配到引号,其他都是可以的,数量上可以为0,也就是引号中间没有内容。单引号和双引号都有可能,所以写了两次。
            // 3、然后把这匹配的三个作为一组,需要全部都进行匹配,数量上可以为0,不需要捕获分组的内容,所以使用了?:
            // 4、最外层是<>
            return str.replace(/<(?:[^'">]|"[^"]*"|'[^']*')*>/g,"");
        }
    
    })(jQuery)

    知识点:

    点击 input 显示下拉层,点击其他地方隐藏下拉层

    这个功能,不能用下面这段代码

        searchInput.on("focus",function(){
            searchList.show();
        }).on("blur",function(){
            searchList.hide();
        });

    因为这里的blur事件与click事件存在冲突
    在选项上按下鼠标时,已经触发了input的blur事件,导致列表隐藏;再出发列表项的点击时,列表已经被隐藏

    需要使用下面这段代码:(注意要阻止冒泡)

        //显示隐藏下拉层
        searchInput.on("focus",function(){
            searchList.show();
        }).on("click",function(){
            return false;//阻止点击时冒泡到document
        });
        $(document).on("click",function(){
            searchList.hide();
        });

    去掉字符串中 html 标签的正则:

        //去掉下拉列表项目的html标签,不然点击后会显示在搜索框中
        function removeHTML(str){
            return str.replace(/<(?:[^'">]|"[^"]*"|'[^']*')*>/g,"");
        }

    示例:<input type="text" value=">" name='username' />
    1、标签中的属性使用的引号 可能是双引号,也可能是单引号,所以匹配引号外面的内容使用^取反,双引号,单引号和>不能获取,其他都是可以获取的。
    2、匹配引号里面的内容,不能匹配到引号,其他都是可以的,数量上可以为0,也就是引号中间没有内容。单引号和双引号都有可能,所以写了两次。
    3、然后把这匹配的三个作为一组,需要全部都进行匹配,数量上可以为0,不需要捕获分组的内容,所以使用了?:
    4、最外层是<>


     面向对象方式封装搜索框功能

    search.js

    (function($){
        "use strict";
    
        function Search(elem,options){
            this.elem=elem;//已经是传入的jquery对象
            this.options=options;
    
            this.form=this.elem.find(".search-form");
            this.input=this.elem.find(".search-input");
            this.list=this.elem.find(".search-list");
            
            //绑定提交事件,事件代理
            this.elem.on("click",".search-btn",$.proxy(this.submit,this));
            //如果设置了自动完成
            if(this.options.autocomplete) this.autocomplete();
        }
    
        //默认参数
        Search.defaults={
            autocomplete:false,
            url:"https://suggest.taobao.com/sug?code=utf-8&_ksTS=1484204931352_18291&callback=jsonp18292&k=1&area=c2c&bucketid=6&q=",
            css3:false,
            js:false,
            animation:"fade"
        }
    
        Search.prototype.submit=function(){
            if($.trim(this.input.val())==="") return false;
            this.form.submit();
        }
    
        Search.prototype.autocomplete=function(){
            this.input.on("input",$.proxy(this.getData,this));
            this.list.showHide(this.options);//向showhide组件传参,初始化
    
            //显示隐藏下拉层
            this.input.on("focus",$.proxy(this.showList,this))
                      .on("click",function(){
                          return false;//阻止点击时冒泡到document
                      });
            $(document).on("click",$.proxy(this.hideList,this));
        }
    
        Search.prototype.getData=function(){
            var self=this;
    
            $.ajax({
                url:this.options.url+encodeURIComponent($.trim(this.input.val())),
                dataType:"jsonp"
            }).done(function(data){
                //发送data数据,触发事件
                self.elem.trigger("search-getData",[data,self.list]);//数据需要用数组形式
            }).fail(function(){
                //发送失败数据,触发事件
                self.elem.trigger("search-noData",[self.list]);
            });    
        }
    
        Search.prototype.showList=function(){
            //list里有内容才显示
            if(this.list.children().length===0) return;
            this.list.showHide("show");//使用showhide组件的show方法
        }
    
        Search.prototype.hideList=function(){
            this.list.showHide("hide");//使用showhide组件的hide方法
        }
    
        Search.prototype.setInput=function(val){
            this.input.val(val);
        }
    
        //插件形式
        $.fn.extend({
            search:function(opt,value){
                return this.each(function(){
                    var ui=$(this);
                    var search=ui.data("search");
                    //opt是参数对象
                    var options=$.extend({},Search.defaults,ui.data(),typeof opt==="object"&&opt);
                    
                    //单例:一个DOM元素对应一个实例,如果已经存在则不需要反复实例化
                    if(!search){
                        search=new Search(ui,options);
                        ui.data("search",search);
                    }
                    
                    //暴露出一些方法供外部调用
                    if(typeof search[opt]==="function"){
                        search[opt](value);
                    }
                });
            }
        });
    
    })(jQuery)

    index.js

    // 不要暴露在全局,使用匿名函数自执行
    (function($){
    
        "use strict";
        
    //menu
        //绑定事件 显示之前加载数据
        $(".dropdown").on("dropdown-show",function(e){
    
            var ui=$(this);
            var dataLoad=ui.data("load");
    
            if(!dataLoad) return;
    
            if(!ui.data("loaded")){
    
                var list=ui.find(".dropdown-list");
                var html="";
    
                setTimeout(function(){
                    $.getJSON(dataLoad,function(data){
                        for(var i=0;i<data.length;i++){
                            console.log(data[i]);
                            html+='<li class="menu-item"><a href="'+data[i]["url"]+'">'+data[i]["name"]+'</a></li>';
                        }
                        list.html(html);    
                        ui.data("loaded",true);
    
                    });                
                },500);
            }    
        });
    
        //插件形式调用
        $(".dropdown").dropdown({
            css3:true,
            js:true
        });
    
    //search
        var headerSearch=$("#header-search");
        var html="";
        var maxNum=10;//最大显示数据量
    
        headerSearch.search({
            autocomplete:true,
            css3:false,
            js:false,
            animation:"fade"
        });
    
        //接收事件
        headerSearch.on("search-getData",function(e,data,list){
            //console.log(e.type);
            //console.log(data);
            
            var ui=$(this);
            //获取数据之后的处理
            html=createHeaderList(data,maxNum);
            list.html(html);
    
            if(html){
                ui.search("showList");
            }else{
                ui.search("hideList");
            }
            
        });
    
        headerSearch.on("search-noData",function(e,list){
            ui.search("hideList");//隐藏下拉列表
            list.html("");//清空内容
        });
    
        headerSearch.on("click",".search-item",function(){
            headerSearch.search("setInput",$(this).text());
            headerSearch.search("submit");
        });
    
        //创建header中搜索框的下拉列表结构
        function createHeaderList(data,maxNum){
            var html="";
            var dataNum=data["result"].length;//实际数据量
    
            if(dataNum===0) return "";
    
            for(var i=0;i<dataNum;i++){
                if(i>=maxNum) break;
                html+='<li class="search-item text-ellipsis" title="'+data["result"][i][0]+'">'+data["result"][i][0]+'</li>';
            }
            return html;
        }
    
    })(jQuery);

     接下来进行代码的优化:

    1、上面这句代码是对DOM的操作,比较耗费性能。优化:引入loaded变量来判断

    2、发送ajax请求时,需要新增判断数据为空的情况

    3、如果一次ajax请求还没完成,就发送了下一次ajax请求,那么会导致返回的数据无法判断是哪一次的。优化:进行下一次请求时先终止之前的请求

    4、搜索框每输入一个字符,就会发送一次ajax请求,即使两次间隔很短;建议:根据用户需求,判断是否需要加入延迟

     优化后的search.js

    (function($){
        "use strict";
    
        function Search(elem,options){
            this.elem=elem;//已经是传入的jquery对象
            this.options=options;
    
            this.form=this.elem.find(".search-form");
            this.input=this.elem.find(".search-input");
            this.list=this.elem.find(".search-list");
    
            this.loaded=false;//是否装载html
            
            //绑定提交事件,事件代理
            this.elem.on("click",".search-btn",$.proxy(this.submit,this));
            //如果设置了自动完成
            if(this.options.autocomplete) this.autocomplete();
        }
    
        //默认参数
        Search.defaults={
            autocomplete:false,
            url:"https://suggest.taobao.com/sug?code=utf-8&_ksTS=1484204931352_18291&callback=jsonp18292&k=1&area=c2c&bucketid=6&q=",
            css3:false,
            js:false,
            animation:"fade",
            delay:200//默认200毫秒延迟
        }
    
        Search.prototype.submit=function(){
            if($.trim(this.input.val())==="") return false;
            this.form.submit();
        }
    
        Search.prototype.autocomplete=function(){
            var self=this;
            var timer=null;
    
            this.input.on("input",function(){
    
                if(self.options.delay){
                    clearTimeout(timer);
                    timer=setTimeout(function(){
                        self.getData();
                    },self.options.delay);                
                }else{
                    self.getData();
                    //delay为0时,不需要开定时器
                    //因为定时器属于异步,即使延迟为0,也会进入排队状态,无法立刻执行
                }
    
            });
    
            this.list.showHide(this.options);//向showhide组件传参,初始化
    
            //显示隐藏下拉层
            this.input.on("focus",$.proxy(this.showList,this))
                      .on("click",function(){
                          return false;//阻止点击时冒泡到document
                      });
            $(document).on("click",$.proxy(this.hideList,this));
        }
    
        Search.prototype.getData=function(){
            var self=this;
            var inputVal=this.input.val();
    
            if(!inputVal) return self.elem.trigger("search-noData");
    
            if(this.jqXHR) this.jqXHR.abort();//进行ajax请求时,先终止之前的请求
            this.jqXHR=$.ajax({
                url:this.options.url+encodeURIComponent($.trim(inputVal)),
                dataType:"jsonp"
            }).done(function(data){
                //发送data数据,触发事件
                self.elem.trigger("search-getData",[data]);//数据需要用数组形式
            }).fail(function(){
                //发送失败数据,触发事件
                self.elem.trigger("search-noData");
            }).always(function(){
                //执行完毕后
                self.jqXHR=null;
            });    
        }
    
        Search.prototype.showList=function(){
            //list里有内容才显示
            if(!this.loaded) return;
            this.list.showHide("show");//使用showhide组件的show方法
        }
    
        Search.prototype.hideList=function(){
            this.list.showHide("hide");//使用showhide组件的hide方法
        }
    
        Search.prototype.setInput=function(val){
            this.input.val(val);
        }
    
        Search.prototype.appendHTML=function(html){
            this.list.html(html);
            this.loaded=!!html;//!!转布尔值,如果html有内容,转为真;否则为假
        }
    
        //插件形式
        $.fn.extend({
            search:function(opt,value){
                return this.each(function(){
                    var ui=$(this);
                    var search=ui.data("search");
                    //opt是参数对象
                    var options=$.extend({},Search.defaults,ui.data(),typeof opt==="object"&&opt);
                    
                    //单例:一个DOM元素对应一个实例,如果已经存在则不需要反复实例化
                    if(!search){
                        search=new Search(ui,options);
                        ui.data("search",search);
                    }
                    
                    //暴露出一些方法供外部调用
                    if(typeof search[opt]==="function"){
                        search[opt](value);
                    }
                });
            }
        });
    
    })(jQuery)

    index.js

    // 不要暴露在全局,使用匿名函数自执行
    (function($){
    
        "use strict";
        
    //menu
        //绑定事件 显示之前加载数据
        $(".dropdown").on("dropdown-show",function(e){
    
            var ui=$(this);
            var dataLoad=ui.data("load");
    
            if(!dataLoad) return;
    
            if(!ui.data("loaded")){
    
                var list=ui.find(".dropdown-list");
                var html="";
    
                setTimeout(function(){
                    $.getJSON(dataLoad,function(data){
                        for(var i=0;i<data.length;i++){
                            console.log(data[i]);
                            html+='<li class="menu-item"><a href="'+data[i]["url"]+'">'+data[i]["name"]+'</a></li>';
                        }
                        list.html(html);    
                        ui.data("loaded",true);
    
                    });                
                },500);
            }    
        });
    
        //插件形式调用
        $(".dropdown").dropdown({
            css3:true,
            js:true
        });
    
    //search
        var headerSearch=$("#header-search");
        var html="";
        var maxNum=10;//最大显示数据量
    
        headerSearch.search({
            autocomplete:true,
            css3:false,
            js:false,
            animation:"fade",
            delay:0
        });
    
        //接收事件
        headerSearch.on("search-getData",function(e,data){
            //console.log(e.type);
            console.log(data);
            
            var ui=$(this);
            //获取数据之后的处理
            html=createHeaderList(data,maxNum);
            ui.search("appendHTML",html);
    
            if(html){
                ui.search("showList");
            }else{
                ui.search("hideList");
            }
            
        }).on("search-noData",function(e){
    
            $(this).search("hideList");//隐藏下拉列表
            $(this).search("appendHTML","");//清空内容
    
        }).on("click",".search-item",function(){
    
            $(this).search("setInput",$(this).text());
            $(this).search("submit");
    
        });
    
        //创建header中搜索框的下拉列表结构
        function createHeaderList(data,maxNum){
            var html="";
            var dataNum=data["result"].length;//实际数据量
    
            if(dataNum===0) return "";
    
            for(var i=0;i<dataNum;i++){
                if(i>=maxNum) break;
                html+='<li class="search-item text-ellipsis" title="'+data["result"][i][0]+'">'+data["result"][i][0]+'</li>';
            }
            return html;
        }
    
    })(jQuery);

    index.html

    <!DOCTYPE html>
    <html lang="zh-CN"><!-- 设置简体中文 -->
    <head>
        <meta charset="UTF-8">
        <title>index</title>
        <link rel="stylesheet" href="css/base.css">
        <link rel="stylesheet" href="css/index.css">
        <link rel="stylesheet" href="css/common.css">
        <!-- css一般放在DOM加载前,防止DOM裸奔 -->
    </head>
    <body>
        <!-- 导航 -->
        <div class="nav-site">
            <div class="container">
                <ul class="fl">
                    <li class="fl"><a href="javascript:;" class="nav-site-login">亲,请登录</a></li>
                    <li class="fl"><a href="javascript:;" class="nav-site-reg link">免费注册</a></li>
                    <li class="fl"><a href="#" class="nav-site-shop link">手机逛慕淘</a></li>
                </ul>
                <ul class="fr">
                    <li class="fl dropdown menu" data-active="menu">
                        <a href="javascript:;" class="dropdown-toggle link transition">我的慕淘<i class="dropdown-arrow iconfont transition">&#xe642;</i></a>
                        <ul class="dropdown-list dropdown-left">
                            <li class="menu-item"><a href="#">已买到的宝贝</a></li>
                            <li class="menu-item"><a href="#">我的足迹</a></li>
                        </ul>
                    </li>
                    <li class="fl dropdown menu" data-active="menu">
                        <a href="javascript:;" class="dropdown-toggle link transition">收藏夹<i class="dropdown-arrow iconfont transition">&#xe642;</i></a>
                        <ul class="dropdown-list dropdown-left">
                            <li class="menu-item"><a href="#">收藏的宝贝</a></li>
                            <li class="menu-item"><a href="#">收藏的店铺</a></li>
                        </ul>
                    </li>
                    <li class="fl dropdown">
                        <a href="javascript:;" class="nav-site-cat link">商品分类</i></a>
                    </li>
                    <li class="fl dropdown menu" data-active="menu" data-load="js/dropdown-seller.json">
                        <a href="javascript:;" class="dropdown-toggle link transition">卖家中心<i class="dropdown-arrow iconfont transition">&#xe642;</i></a>
                        <ul class="dropdown-list dropdown-left">
                            <li class="dropdown-loading"></li>
                            <!-- <li class="menu-item"><a href="#">免费开店</a></li>
                            <li class="menu-item"><a href="#">已卖出的宝贝</a></li>
                            <li class="menu-item"><a href="#">出售中的宝贝</a></li>
                            <li class="menu-item"><a href="#">卖家服务市场</a></li>
                            <li class="menu-item"><a href="#">卖家培训中心</a></li>
                            <li class="menu-item"><a href="#">体验中心</a></li> -->
                        </ul>
                    </li>
                    <li class="nav-site-service fl dropdown menu" data-active="menu">
                        <a href="javascript:;" class="dropdown-toggle link transition">联系客服<i class="dropdown-arrow iconfont transition">&#xe642;</i></a>
                        <ul class="dropdown-list dropdown-right">
                            <li class="menu-item"><a href="#">已买到的宝贝</a></li>
                            <li class="menu-item"><a href="#">我的足迹</a></li>
                        </ul>
                    </li>
                </ul>
            </div>
        </div>
    
        <!-- 头部 -->
        <div class="header">
            <div class="container">
                <!-- h1标签是为了搜索引擎优化,表示重要
                但是页面内不要出现太多 -->
                <h1 class="fl"><a href="#" class="header-logo text-hidden">慕淘网</a></h1>
                <div id="header-search" class="search fl">
                    <!-- 由于没有自己的搜索页,演示时设置为提交到淘宝,参考淘宝设置 -->
                    <form action="https://s.taobao.com/search" class="search-form">
                        <!-- 由于input是内联块,相当于display:inline-block
                        如果换行写,会造成空隙,空隙大小一般是默认字体的一半
                        可以不换行书写,但是可读性较差
                        都添加左浮动可以解决 -->
                        <!-- 设置name才能提交 -->
                        <input type="text" class="search-input fl" name="q" placeholder="灵魂美食一元抢" autocomplete="off">
                        <input type="submit" value="搜索" class="search-btn fl">
                    </form>
                    <ul class="search-list">
                        <!-- <li class="search-item text-ellipsis" title="111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111">111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111</li>
                        <li class="search-item text-ellipsis" title="222">222</li>
                        <li class="search-item text-ellipsis" title="333">333</li> -->
                    </ul>
                </div>
                <div class="header-cart fr"></div>
            </div>
        </div>
    
    <!--     <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
        <script>
            //短路操作,如果cdn的jquery没有引用成功,则会执行后面一句,引入本地jquery
            //括号中的</script>标签会被当做当前标签的结束标签,因此需要转义
            window.jQuery || document.write('<script src="js/jquery.js"></script>');
        </script> -->
        <script src="js/jquery.js"></script>
        <script src="js/transition.js"></script>
        <script src="js/showhide.js"></script>
        <script src="js/dropdown.js"></script>
        <script src="js/search.js"></script>
        <script src="js/index.js"></script>
    </body>
    </html>

    最后,优化之数据缓存

    思路:获取到的数据存入变量、cookie、或是本地存储:session storage / local storage (HTML5) 或是本地数据库

    search.js

    (function($){
        "use strict";
    
        var cache={
            data:{},
            count:0,//数据条数
            addData:function(data,key){
                if(!this.data[key]){
                    this.data[key]=data;
                    this.count++;            
                }
            },
            readData:function(key){
                return this.data[key];
            },
            deleteDataByKey:function(key){
                delete this.data[key];
                this.count--;
            },
            deleteDataByNum:function(num){
                var count=0;
                //对象没有length属性,只能通过for in来遍历
                for(var p in this.data){
                    if(count>=num) break;
                    this.deleteDataByKey(p);
                    this.count++;
                }
            }
    
        };
    
        function Search(elem,options){
            this.elem=elem;//已经是传入的jquery对象
            this.options=options;
    
            this.form=this.elem.find(".search-form");
            this.input=this.elem.find(".search-input");
            this.list=this.elem.find(".search-list");
    
            this.loaded=false;//是否装载html
            
            //绑定提交事件,事件代理
            this.elem.on("click",".search-btn",$.proxy(this.submit,this));
            //如果设置了自动完成
            if(this.options.autocomplete) this.autocomplete();
        }
    
        //默认参数
        Search.defaults={
            autocomplete:false,
            url:"https://suggest.taobao.com/sug?code=utf-8&_ksTS=1484204931352_18291&callback=jsonp18292&k=1&area=c2c&bucketid=6&q=",
            css3:false,
            js:false,
            animation:"fade",
            delay:200//默认200毫秒延迟
        }
    
        Search.prototype.submit=function(){
            if($.trim(this.input.val())==="") return false;
            this.form.submit();
        }
    
        Search.prototype.autocomplete=function(){
            var self=this;
            var timer=null;
    
            this.input.on("input",function(){
    
                if(self.options.delay){
                    clearTimeout(timer);
                    timer=setTimeout(function(){
                        self.getData();
                    },self.options.delay);                
                }else{
                    self.getData();
                    //delay为0时,不需要开定时器
                    //因为定时器属于异步,即使延迟为0,也会进入排队状态,无法立刻执行
                }
    
            });
    
            this.list.showHide(this.options);//向showhide组件传参,初始化
    
            //显示隐藏下拉层
            this.input.on("focus",$.proxy(this.showList,this))
                      .on("click",function(){
                          return false;//阻止点击时冒泡到document
                      });
            $(document).on("click",$.proxy(this.hideList,this));
        }
    
        Search.prototype.getData=function(){
            var self=this;
            var inputVal=this.input.val();
    
            if(!inputVal) return self.elem.trigger("search-noData");
    
            //判断是否已有缓存
            if(cache.readData(inputVal)) return self.elem.trigger("search-getData",[cache.readData(inputVal)]);
    
            if(this.jqXHR) this.jqXHR.abort();//进行ajax请求时,先终止之前的请求
            this.jqXHR=$.ajax({
                url:this.options.url+encodeURIComponent($.trim(inputVal)),
                dataType:"jsonp"
            }).done(function(data){
                //发送data数据,触发事件            
                cache.addData(data,inputVal);//添加缓存
                console.log(cache.data);
                console.log(cache.count);
                self.elem.trigger("search-getData",[data]);//数据需要用数组形式
            }).fail(function(){
                //发送失败数据,触发事件
                self.elem.trigger("search-noData");
            }).always(function(){
                //执行完毕后
                self.jqXHR=null;
            });    
        }
    
        Search.prototype.showList=function(){
            //list里有内容才显示
            if(!this.loaded) return;
            this.list.showHide("show");//使用showhide组件的show方法
        }
    
        Search.prototype.hideList=function(){
            this.list.showHide("hide");//使用showhide组件的hide方法
        }
    
        Search.prototype.setInput=function(val){
            this.input.val(val);
        }
    
        Search.prototype.appendHTML=function(html){
            this.list.html(html);
            this.loaded=!!html;//!!转布尔值,如果html有内容,转为真;否则为假
        }
    
        //插件形式
        $.fn.extend({
            search:function(opt,value){
                return this.each(function(){
                    var ui=$(this);
                    var search=ui.data("search");
                    //opt是参数对象
                    var options=$.extend({},Search.defaults,ui.data(),typeof opt==="object"&&opt);
                    
                    //单例:一个DOM元素对应一个实例,如果已经存在则不需要反复实例化
                    if(!search){
                        search=new Search(ui,options);
                        ui.data("search",search);
                    }
                    
                    //暴露出一些方法供外部调用
                    if(typeof search[opt]==="function"){
                        search[opt](value);
                    }
                });
            }
        });
    
    })(jQuery)

  • 相关阅读:
    二维线性表 list实现
    行测题
    邻接表
    链表中插入和删除结点
    linux监控指标和命令
    lr测试结果分析
    python 装饰器 decorator
    并查集 PID331 / 家族
    素数环 dfs+回溯
    catch the cow bfs
  • 原文地址:https://www.cnblogs.com/chenyingying0/p/12347806.html
Copyright © 2011-2022 走看看