index.html header structure and style
Design sketch
Static style
Part of index.html
<!-- head --> <div class="header"> <div class="container"> <!-- h1 Tag is for search engine optimization, indicating importance But don't show too much in the page --> <h1 class="fl"><a href="#" class="header-logo text-hidden">Mu Tao net</a></h1> <div class="search fl"> <!-- Since there is no search page of its own, it is set to submit to Taobao during demonstration. Refer to Taobao settings --> <form action="https://s.taobao.com/search"> <!-- Because input Is an inline block, equivalent to display:inline-block If you wrap, there will be gaps, which are usually half the size of the default font Can write without wrapping, but poor readability All add left float to solve --> <!-- Set up name Submission --> <input type="text" class="search-input fl" name="q" placeholder="Soul food" autocomplete="off"> <input type="submit" value="search" 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>
New common style of search box component in common.css
/*Search box component 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%;/*Height of parent container*/ left:-1px; border:1px solid #cfd2d5; padding:0 10px; } .search-item{ height:24px; line-height:24px; }
New unique style in header in index.css
/*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; }
Import search.js file
Here we add the following differences of triggering conditions for textbox events:
Change text box content change + blur
keypress key is triggered. If the mouse does not lift the continuous key, it will be triggered continuously
keyup key release trigger, no matter what key is pressed (including up and down arrows and other wordless symbols), and the pasted text cannot be triggered
The difference between input text input and change is that it can be triggered without blur; mouse paste can also be triggered (poor compatibility: not supported under IE8)
To sum up, the best choice is input, but sometimes for compatibility, you can only choose keyup and make some constraint modifications yourself
View the form form submission action of Taobao Search
//s.taobao.com/search
When using the form, you need to add https: Protocol in front of Taobao
Namely: https://s.taobao.com/search
View the name attribute of Taobao search input box
name="q"
View the url address of ajax request when Taobao submits
1. Open the web address, open the console, find the network, and click JS below
2. You can use the button in the green box to clear the content below, and then write the content in the input box, and the information will come out in the place of the Name below
3. Click any one of them to go in, and the Headers on the right will appear. You can see the Request URL pasted and copied in the browser address bar.
Add search validation and data acquisition capabilities:
search.js
(function($){ "use strict"; //Verification var search=$(".search"), searchInput=search.find(".search-input"), searchBtn=search.find(".search-btn"), searchList=search.find(".search-list"); searchBtn.on("click",function(){ //submit The default behavior of the button is to submit the form, return false Can block default behavior //$.trim() Remove the spaces on both sides of the string to prevent no content submission if($.trim(searchInput.val())==="") return false; }); //Auto completion 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 For cross domain success:function(data){ console.log(data); }, error:function(data){ console.log(error); } }); }); })(jQuery)
Because jQuery.ajax returns the jqXHR object, which is a superset of the browser's native XMLHttpRequest object, in order to make the callback function name uniform and easy to use in $.ajax, jqXHR provides.error(),.success(),.complete()
Due to the version upgrade, there are three corresponding methods, namely. fail(),. done(),. always()
Use done(), fail(), always() to avoid code nesting in ajax and facilitate reading
So $. ajax can be modified as follows to avoid callback asynchronously:
// Asynchronous avoid callback $.ajax({ url:url, timeout:1,//The common cause of failure is timeout, which is set to 1ms for demonstration dataType:"jsonp" }).done(function(data){//Successful implementation console.log(data); }).fail(function(){//Failure execution console.log("fail"); }).always(function(){//Always execute console.log("always"); });
There are many reasons for failure, of which timeout is a very common one
To demonstrate timeout, set timeout:1 (1 ms)
$. trim(searchInput.val()) is the utf-8 encoding used by default
If the page is in another encoding format, such as gbk, reading data may fail due to encoding problems
Therefore, encodeuriccomponent() is used to solve the coding problem
1. The encodeuriccomponent (URIstring) function encodes a string as a URI component. The return value is a copy of URIstring. Some characters in the string will be replaced by a hexadecimal escape sequence. In short, the function is to encode, to be recognized by the background, and the background development language has corresponding decoding api, so that the data can be successfully returned.
2. The encoding of web page will affect the encoding of data when sending request, so it is necessary to encode when it is inconsistent.
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()));
Generate pull-down data structure
(function($){ "use strict"; //Verification var search=$(".search"), searchInput=search.find(".search-input"), searchBtn=search.find(".search-btn"), searchList=search.find(".search-list"); searchBtn.on("click",function(){ //submit The default behavior of the button is to submit the form, return false Can block default behavior //$.trim() Remove the spaces on both sides of the string to prevent no content submission if($.trim(searchInput.val())==="") return false; }); //Auto completion 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())); // Asynchronous avoid callback $.ajax({ url:url, dataType:"jsonp" }).done(function(data){//Successful implementation //console.log(data["result"]); var html=""; var dataNum=data["result"].length;//Actual data volume var maxNum=10;//Maximum display data 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(){//Failure execution searchList.hide().html(""); }).always(function(){//Always execute console.log("always"); }); }); })(jQuery)
By the way, comment out the previous part in 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>
Effect
Event agent and show hidden drop-down layer
(function($){ "use strict"; //Verification 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 You can block the default behavior, that is, form submission //$.trim() Remove the spaces on both sides of the string to prevent no content submission if($.trim(searchInput.val())==="") return false; }); //Auto completion 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())); // Asynchronous avoid callback $.ajax({ url:url, dataType:"jsonp" }).done(function(data){//Successful implementation //console.log(data["result"]); var html=""; var dataNum=data["result"].length;//Actual data volume var maxNum=10;//Maximum display data 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(){//Failure execution searchList.hide().html(""); }).always(function(){//Always execute console.log("always"); }); }); //jquery Event agent for //The event is bound to the parent element. The first parameter is the event, the second parameter is the children of the proxied elements, and the third parameter is the function //In function $(this)Points to the child element being proxied searchList.on("click",".search-item",function(){ searchInput.val(removeHTML($(this).html())); searchForm.submit(); }); //Show hidden dropdown // searchInput.on("focus",function(){ // searchList.show(); // }).on("blur",function(){ // searchList.hide(); // }); //The above method is not feasible, which will lead to the failure of clicking list items //because blur Incident and click Event conflict //Because when you press the mouse over an option, it's triggered input Of blur Event, which causes the list to be hidden. When clicking the list item again, the list has been hidden searchInput.on("focus",function(){ searchList.show(); }).on("click",function(){ return false;//Prevent bubbling when clicking document }); $(document).on("click",function(){ searchList.hide(); }); //Remove the html Tag, otherwise it will be displayed in the search box after clicking function removeHTML(str){ // Example:<input type="text" value=">" name='username' /> // 1,The quotation mark used for the attribute in the tag may be double quotation mark or single quotation mark, so it is used to match the content outside the quotation mark^Reverse, double, single and>It can't be obtained. Everything else can be obtained. // 2,Match the content in quotation marks, not to quotation marks, others are OK, the quantity can be 0, that is, there is no content in the middle of quotation marks. Single and double quotes are possible, so write twice. // 3,Then take the three matched ones as a group, all of them need to be matched, which can be 0 in quantity, and there is no need to capture the grouped content, so we use the?: // 4,The outermost layer is<> return str.replace(/<(?:[^'">]|"[^"]*"|'[^']*')*>/g,""); } })(jQuery)
Knowledge points:
Click input to display the pull-down layer, and click other places to hide the pull-down layer
This function cannot use the following code
searchInput.on("focus",function(){ searchList.show(); }).on("blur",function(){ searchList.hide(); });
Because the blur event here conflicts with the click event
When you press the mouse on the option, the blue event of input has been triggered, which causes the list to be hidden; when you click the list item again, the list has been hidden
You need to use the following code: (note to prevent bubbling)
//Show hidden dropdown searchInput.on("focus",function(){ searchList.show(); }).on("click",function(){ return false;//Prevent bubbling when clicking document }); $(document).on("click",function(){ searchList.hide(); });
Remove the regularity of html tags in the string:
//Remove the html Tag, otherwise it will be displayed in the search box after clicking function removeHTML(str){ return str.replace(/<(?:[^'">]|"[^"]*"|'[^']*')*>/g,""); }
Example: < input type = "text" value = "> name ='username '/ >
1. The quotation marks used for the attributes in the tag may be double quotation marks or single quotation marks, so the contents outside the matching quotation marks can be reversed with ^, double quotation marks, single quotation marks and > cannot be obtained, and others can be obtained.
2. Match the content in quotation marks, not to quotation marks, others are OK, the quantity can be 0, that is, there is no content in the middle of quotation marks. Single and double quotes are possible, so write twice.
3. Then take the three matched ones as a group, all of them need to be matched, which can be 0 in quantity, and no need to capture the contents of the group. Therefore, you use the?:
4. The outermost layer is < >
Object oriented encapsulation of search box function
search.js
(function($){ "use strict"; function Search(elem,options){ this.elem=elem;//Already passed in jquery object this.options=options; this.form=this.elem.find(".search-form"); this.input=this.elem.find(".search-input"); this.list=this.elem.find(".search-list"); //Binding submit event, event agent this.elem.on("click",".search-btn",$.proxy(this.submit,this)); //If autocomplete is set if(this.options.autocomplete) this.autocomplete(); } //Default parameters 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);//towards showhide Component parameters, initialization //Show hidden dropdown this.input.on("focus",$.proxy(this.showList,this)) .on("click",function(){ return false;//Prevent bubbling when clicking 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){ //Send out data Data, triggering events self.elem.trigger("search-getData",[data,self.list]);//Data needs to be in array form }).fail(function(){ //Send failure data, trigger event self.elem.trigger("search-noData",[self.list]); }); } Search.prototype.showList=function(){ //list There's something in it if(this.list.children().length===0) return; this.list.showHide("show");//Use showhide Component show Method } Search.prototype.hideList=function(){ this.list.showHide("hide");//Use showhide Component hide Method } Search.prototype.setInput=function(val){ this.input.val(val); } //Plug-in form $.fn.extend({ search:function(opt,value){ return this.each(function(){ var ui=$(this); var search=ui.data("search"); //opt Is a parameter object var options=$.extend({},Search.defaults,ui.data(),typeof opt==="object"&&opt); //Single example: one DOM Element corresponds to an instance. If it already exists, it does not need to be instantiated repeatedly if(!search){ search=new Search(ui,options); ui.data("search",search); } //Exposed methods for external calls if(typeof search[opt]==="function"){ search[opt](value); } }); } }); })(jQuery)
index.js
// Do not expose to the global, use anonymous function to self execute (function($){ "use strict"; //menu //Load data before binding event display $(".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); } }); //Plug in call $(".dropdown").dropdown({ css3:true, js:true }); //search var headerSearch=$("#header-search"); var html=""; var maxNum=10;//Maximum display data headerSearch.search({ autocomplete:true, css3:false, js:false, animation:"fade" }); //Receiving events headerSearch.on("search-getData",function(e,data,list){ //console.log(e.type); //console.log(data); var ui=$(this); //Processing after data acquisition 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");//Hide dropdown list.html("");//Empty content }); headerSearch.on("click",".search-item",function(){ headerSearch.search("setInput",$(this).text()); headerSearch.search("submit"); }); //Establish header Drop down list structure of search box in function createHeaderList(data,maxNum){ var html=""; var dataNum=data["result"].length;//Actual data volume 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);
Next, optimize the code:
1. The above code is for DOM operation, which consumes performance. Optimization: introduce the loaded variable to judge
2. When sending an ajax request, you need to add a new case where the judgment data is empty
3. If the next ajax request is sent before the completion of an ajax request, the returned data cannot be determined. Optimization: terminate the previous request before the next request
4. Every time a character is entered in the search box, an ajax request will be sent, even if the interval between two requests is very short. Suggestion: judge whether to add delay according to the user's needs
Optimized search.js
(function($){ "use strict"; function Search(elem,options){ this.elem=elem;//Already passed in jquery object 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;//Is it loaded? html //Binding submit event, event agent this.elem.on("click",".search-btn",$.proxy(this.submit,this)); //If autocomplete is set if(this.options.autocomplete) this.autocomplete(); } //Default parameters 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//Default 200ms delay } 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 When it is 0, the timer does not need to be turned on //Because the timer is asynchronous, even if the delay is 0, it will enter the queued state and cannot be executed immediately } }); this.list.showHide(this.options);//towards showhide Component parameters, initialization //Show hidden dropdown this.input.on("focus",$.proxy(this.showList,this)) .on("click",function(){ return false;//Prevent bubbling when clicking 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();//Conduct ajax When requesting, terminate the previous request first this.jqXHR=$.ajax({ url:this.options.url+encodeURIComponent($.trim(inputVal)), dataType:"jsonp" }).done(function(data){ //Send out data Data, triggering events self.elem.trigger("search-getData",[data]);//Data needs to be in array form }).fail(function(){ //Send failure data, trigger event self.elem.trigger("search-noData"); }).always(function(){ //After execution self.jqXHR=null; }); } Search.prototype.showList=function(){ //list There's something in it if(!this.loaded) return; this.list.showHide("show");//Use showhide Component show Method } Search.prototype.hideList=function(){ this.list.showHide("hide");//Use showhide Component hide Method } Search.prototype.setInput=function(val){ this.input.val(val); } Search.prototype.appendHTML=function(html){ this.list.html(html); this.loaded=!!html;//!!To Boolean, if html If there is content, it will be true; otherwise, it will be false } //Plug-in form $.fn.extend({ search:function(opt,value){ return this.each(function(){ var ui=$(this); var search=ui.data("search"); //opt Is a parameter object var options=$.extend({},Search.defaults,ui.data(),typeof opt==="object"&&opt); //Single example: one DOM Element corresponds to an instance. If it already exists, it does not need to be instantiated repeatedly if(!search){ search=new Search(ui,options); ui.data("search",search); } //Exposed methods for external calls if(typeof search[opt]==="function"){ search[opt](value); } }); } }); })(jQuery)
index.js
// Do not expose to the global, use anonymous function to self execute (function($){ "use strict"; //menu //Load data before binding event display $(".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); } }); //Plug in call $(".dropdown").dropdown({ css3:true, js:true }); //search var headerSearch=$("#header-search"); var html=""; var maxNum=10;//Maximum display data headerSearch.search({ autocomplete:true, css3:false, js:false, animation:"fade", delay:0 }); //Receiving events headerSearch.on("search-getData",function(e,data){ //console.log(e.type); console.log(data); var ui=$(this); //Processing after data acquisition 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");//Hide dropdown $(this).search("appendHTML","");//Empty content }).on("click",".search-item",function(){ $(this).search("setInput",$(this).text()); $(this).search("submit"); }); //Establish header Drop down list structure of search box in function createHeaderList(data,maxNum){ var html=""; var dataNum=data["result"].length;//Actual data volume 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"><!-- Set simplified Chinese --> <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 Generally placed on DOM Before loading, prevent DOM Streaking --> </head> <body> <!-- Navigation --> <div class="nav-site"> <div class="container"> <ul class="fl"> <li class="fl"><a href="javascript:;" class="nav-site-login">Dear, please log in</a></li> <li class="fl"><a href="javascript:;" class="nav-site-reg link">Free registration</a></li> <li class="fl"><a href="#" class="nav-site-shop link">Mobile phone shopping</a></li> </ul> <ul class="fr"> <li class="fl dropdown menu" data-active="menu"> <a href="javascript:;" class="dropdown-toggle link transition">My Mu Tao<i class="dropdown-arrow iconfont transition"></i></a> <ul class="dropdown-list dropdown-left"> <li class="menu-item"><a href="#">Bought baby</a></li> <li class="menu-item"><a href="#">My Tracks</a></li> </ul> </li> <li class="fl dropdown menu" data-active="menu"> <a href="javascript:;" class="dropdown-toggle link transition">Favorites<i class="dropdown-arrow iconfont transition"></i></a> <ul class="dropdown-list dropdown-left"> <li class="menu-item"><a href="#">Treasure of collection</a></li> <li class="menu-item"><a href="#">Collection shop</a></li> </ul> </li> <li class="fl dropdown"> <a href="javascript:;" class="nav-site-cat link">Commodity classification</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">Seller Center<i class="dropdown-arrow iconfont transition"></i></a> <ul class="dropdown-list dropdown-left"> <li class="dropdown-loading"></li> <!-- <li class="menu-item"><a href="#"> free shop</a></li> <li class="menu-item"><a href="#"> sold baby</a></li> <li class="menu-item"><a href="#"> baby on sale</a></li> <li class="menu-item"><a href="#"> seller service market</a></li> <li class="menu-item"><a href="#"> seller Training Center</a></li> <li class="menu-item"><a href="#">Experience Center</a></li> --> </ul> </li> <li class="nav-site-service fl dropdown menu" data-active="menu"> <a href="javascript:;" class="dropdown-toggle link transition">Contact customer service<i class="dropdown-arrow iconfont transition"></i></a> <ul class="dropdown-list dropdown-right"> <li class="menu-item"><a href="#">Bought baby</a></li> <li class="menu-item"><a href="#">My Tracks</a></li> </ul> </li> </ul> </div> </div> <!-- head --> <div class="header"> <div class="container"> <!-- h1 Tag is for search engine optimization, indicating importance But don't show too much in the page --> <h1 class="fl"><a href="#" class="header-logo text-hidden">Mu Tao net</a></h1> <div id="header-search" class="search fl"> <!-- Since there is no search page of its own, it is set to submit to Taobao during demonstration. Refer to Taobao settings --> <form action="https://s.taobao.com/search" class="search-form"> <!-- Because input Is an inline block, equivalent to display:inline-block If you wrap, there will be gaps, which are usually half the size of the default font Can write without wrapping, but poor readability All add left float to solve --> <!-- Set up name Submission --> <input type="text" class="search-input fl" name="q" placeholder="Soul food" autocomplete="off"> <input type="submit" value="search" 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> //Short circuit operation. If the jquery of cdn is not referenced successfully, the following sentence will be executed to introduce the local jquery //The < \ / script > tag in brackets will be used as the end tag of the current tag, so it needs to be escaped 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>
Finally, optimized data caching
Idea: store the acquired data into variables, cookie s, or local storage: session storage / local storage (HTML5) or local database
search.js
(function($){ "use strict"; var cache={ data:{}, count:0,//Number of data bars 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; //No object length Property, only through for in To traverse for(var p in this.data){ if(count>=num) break; this.deleteDataByKey(p); this.count++; } } }; function Search(elem,options){ this.elem=elem;//Already passed in jquery object 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;//Is it loaded? html //Binding submit event, event agent this.elem.on("click",".search-btn",$.proxy(this.submit,this)); //If autocomplete is set if(this.options.autocomplete) this.autocomplete(); } //Default parameters 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//Default 200ms delay } 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 When it is 0, the timer does not need to be turned on //Because the timer is asynchronous, even if the delay is 0, it will enter the queued state and cannot be executed immediately } }); this.list.showHide(this.options);//towards showhide Component parameters, initialization //Show hidden dropdown this.input.on("focus",$.proxy(this.showList,this)) .on("click",function(){ return false;//Prevent bubbling when clicking 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"); //Determine whether there is a cache if(cache.readData(inputVal)) return self.elem.trigger("search-getData",[cache.readData(inputVal)]); if(this.jqXHR) this.jqXHR.abort();//Conduct ajax When requesting, terminate the previous request first this.jqXHR=$.ajax({ url:this.options.url+encodeURIComponent($.trim(inputVal)), dataType:"jsonp" }).done(function(data){ //Send out data Data, triggering events cache.addData(data,inputVal);//Add cache console.log(cache.data); console.log(cache.count); self.elem.trigger("search-getData",[data]);//Data needs to be in array form }).fail(function(){ //Send failure data, trigger event self.elem.trigger("search-noData"); }).always(function(){ //After execution self.jqXHR=null; }); } Search.prototype.showList=function(){ //list There's something in it if(!this.loaded) return; this.list.showHide("show");//Use showhide Component show Method } Search.prototype.hideList=function(){ this.list.showHide("hide");//Use showhide Component hide Method } Search.prototype.setInput=function(val){ this.input.val(val); } Search.prototype.appendHTML=function(html){ this.list.html(html); this.loaded=!!html;//!!To Boolean, if html If there is content, it will be true; otherwise, it will be false } //Plug-in form $.fn.extend({ search:function(opt,value){ return this.each(function(){ var ui=$(this); var search=ui.data("search"); //opt Is a parameter object var options=$.extend({},Search.defaults,ui.data(),typeof opt==="object"&&opt); //Single example: one DOM Element corresponds to an instance. If it already exists, it does not need to be instantiated repeatedly if(!search){ search=new Search(ui,options); ui.data("search",search); } //Exposed methods for external calls if(typeof search[opt]==="function"){ search[opt](value); } }); } }); })(jQuery)