基于jquery實(shí)現(xiàn)智能提示控件intellSeach.js
一、需求
我們經(jīng)常會(huì)遇到【站內(nèi)搜索】的需求,為了提高用戶體驗(yàn),我們希望能做到像百度那樣的即時(shí)智能提示。例如:某公司人事管理系統(tǒng),想搜索李XX,只要輸入“李”,系統(tǒng)自然會(huì)提示一些姓李的員工,這樣方便用戶使用。說(shuō)白了,就是用戶邊輸入,系統(tǒng)會(huì)提示相關(guān)的結(jié)果;或者,當(dāng)用戶點(diǎn)擊搜索框時(shí),就推薦一些內(nèi)容,如360、百度都會(huì)提示今天的主要新聞或搜索量大的內(nèi)容。
jquery 已經(jīng)有一個(gè)這樣的插件了,叫 autocomplete, 但我覺(jué)得不好用。關(guān)于autocomplete的介紹也很多,有興趣的朋友可以去試試。
看標(biāo)題就知道,這里只是分享一個(gè)插件,不會(huì)討論后臺(tái)搜索的相關(guān)算法和過(guò)程,也就是說(shuō),后臺(tái)返回特定格式的數(shù)據(jù),控件負(fù)責(zé)渲染結(jié)果呈現(xiàn)。ok,先看一下效果圖:
樣式與控件無(wú)關(guān),只需要一個(gè) input text 就可以了。
二、參數(shù)說(shuō)明
控件以json格式作為傳輸格式。參數(shù)比較多,大部分都有默認(rèn)值(具體看源碼),有些可能不常用,保持默認(rèn)即可。如下:
url: 請(qǐng)求地址。如:Handler.ashx, 后臺(tái)獲取數(shù)據(jù)的地址
property: 要顯示的json對(duì)象的屬性。如果我們直接返回["tom","tom cat","tom2"] 這樣的形式,那么該屬性可以不用設(shè)置;但有時(shí)候我們會(huì)返回[{"Name":"tom","ID":"001"},{"Name":"tom cat","ID":"002"},{"Name":"tom2","ID":"003"}] 這樣的形式,顯示的是Name,那么設(shè)置該屬性為"Name"即可。至于我們想在點(diǎn)擊的時(shí)候獲得點(diǎn)擊的項(xiàng)的ID,通過(guò)點(diǎn)擊事件即可。
itemNumber: 顯示的項(xiàng)數(shù)目。
isEmptyRequest: focus時(shí),空白是否發(fā)起請(qǐng)求。就像前面說(shuō)的,如果點(diǎn)擊搜索框時(shí)(此時(shí)沒(méi)有內(nèi)容),想要推薦一些內(nèi)容,設(shè)置該屬性為true,即會(huì)發(fā)起請(qǐng)求。
defaultValue: 默認(rèn)值。通常會(huì)是:“請(qǐng)輸入關(guān)鍵詞...” 這類的提示。
width: 下拉列表寬度。
aligner: 要對(duì)齊的元素。
maxHeight: 最大高度。如果設(shè)置該高度,超過(guò)時(shí)就會(huì)出現(xiàn)滾動(dòng)條。
ajax:{
timeout: 超時(shí)時(shí)間
cache: 是否緩存
},
event:{
setData: 發(fā)送請(qǐng)求前觸發(fā)。用于設(shè)置參數(shù)
itemClick: 點(diǎn)擊項(xiàng)觸發(fā)
enterKeydown: 按下enter鍵觸發(fā)
beforeRender: 所有項(xiàng)呈現(xiàn)前觸發(fā)
endRender: 所有項(xiàng)呈現(xiàn)后觸發(fā)
itemBeforeRender: 項(xiàng)呈現(xiàn)前觸發(fā)
itemAfterRender: 項(xiàng)呈現(xiàn)后觸發(fā)
beforeSend: 發(fā)送請(qǐng)求前觸發(fā)。用戶設(shè)置請(qǐng)求頭部參數(shù)等,相當(dāng)于jquery ajax 的 beforeSend。
}
event 里的方法都會(huì)在適當(dāng)?shù)臅r(shí)候觸發(fā),需要注意的是,所有方法都接收一個(gè)參數(shù),該參數(shù)是一個(gè)對(duì)象,有4個(gè)屬性,某些情況如果沒(méi)有該屬性的,則為空。包括如下屬性:
jthis: input 的 jQuery 對(duì)象。
jItem: 項(xiàng)的 jQuery 對(duì)象。
data: 返回的 json 字符串。如果在前臺(tái)需要對(duì)返回 json 再進(jìn)行處理,那么可以通過(guò) data 屬性獲得,處理完成后,需要將 json 字符串 return。
event: 事件對(duì)象,如按下 enter 時(shí)的事件對(duì)象。
三、例子
使用例子:
$("#search").intellSearch({ url:"Handler.ashx", property:"Name", itemNumber:5, isEmptyRequest:false, defaultValue:"請(qǐng)輸入關(guān)鍵字...", width:$("#search").width() + 2, maxHeight:-1, event:{ itemClick:function(obj){ alert(obj.item.ID); }, enterKeydown:function(obj){ if(obj.item){ alert("有當(dāng)前項(xiàng)"); }else{ alert("沒(méi)有當(dāng)前項(xiàng)"); } } } });
四、總結(jié)
如果你還有自己的邏輯需要處理,也支持鏈?zhǔn)秸{(diào)用,大可以這樣寫(xiě) $("#search").intellSearch({參數(shù)...}).focus(function(){你的處理...});
分享該插件希望能幫助到有需要的朋友,主要用于學(xué)習(xí)。由于是v1.0,可能還有一些bug,有發(fā)現(xiàn)的朋友也可以告訴我,我會(huì)及時(shí)修正?! ?/p>
附源代碼
js代碼
/*搜索智能提示 v1.0 date:2015.09.08 */ ;(function(w,$){ $.fn.intellSearch = function(options){ var jthis = this; var _dftOpts = { url:"",//請(qǐng)求地址或數(shù)組 property:"",//要顯示的json對(duì)象的屬性 itemNumber:5,//顯示的條數(shù) isEmptyRequest:false,//focus空白是否發(fā)起請(qǐng)求 defaultValue:"",//默認(rèn)值 width:0,//列表寬度 aligner:jthis,//要對(duì)齊的元素 maxHeight:-1,//最大高度 ajax:{ timeout:3000,//超時(shí)時(shí)間 cache:true//是否緩存 }, event:{ /*參數(shù)說(shuō)明:parameter:{jthis:"jq input",jItem:"jq item",data:"json result",event:"event"}*/ setData:null,//設(shè)置參數(shù) itemClick:null,//點(diǎn)擊項(xiàng)觸發(fā) enterKeydown:null,//按下enter鍵觸發(fā) beforeRender:null,//所有項(xiàng)呈現(xiàn)前觸發(fā) endRender:null,//所有項(xiàng)呈現(xiàn)后觸發(fā) itemBeforeRender:null,//項(xiàng)呈現(xiàn)前觸發(fā) itemAfterRender:null,//項(xiàng)呈現(xiàn)后觸發(fā) beforeSend:null//發(fā)送請(qǐng)求前觸發(fā) } }; $.extend(_dftOpts,options); if(!_dftOpts.url){ throw Error("url不能為空!"); } var jResult; var _value = ""; var _ajax = _dftOpts.ajax; var _event = _dftOpts.event; var _cache = []; var _focusCount = 0;//防止focus觸發(fā)多次(sogou) /*on window*/ window.intellObj = window.intellObj || {}; /*for global event*/ window.intellDocumentClick = window.intellDocumentClick || function(e){ if(!window.intellObj.jthis){ return; } if(e.target !== window.intellObj.jthis[0]){ setIntellObj(null); } } window.intellDocumentKeydown = window.intellDocumentKeydown || function(e){ var jthis = window.intellObj.jthis; if(!jthis){ return; } var code = e.keyCode; var value = window.intellObj.value; var jResult,jCurItem,keyword; if(code === 13 || code === 38 || code === 40){ jResult = window.intellObj.jResult; jItems = jResult.find("li"); jCurItem = jResult.find("li.cur"); if(code === 13){ if(jCurItem.length > 0){ jCurItem.click(); }else{ setIntellObj(null); if(_event.enterKeydown){ _event.enterKeydown({"jthis":jthis,"event":e}); } } jthis.blur(); }else if(jItems.length > 0){ if(code === 38){ if(jCurItem.length <= 0){ jCurItem = jItems.last(); jCurItem.addClass("cur"); keyword = jCurItem.text(); }else{ var index = jCurItem.index(); jCurItem.removeClass("cur"); if(index <= 0){ keyword = value; }else{ jCurItem = jItems.eq(index-1); jCurItem.addClass("cur"); keyword = jCurItem.text(); } } jthis.val(keyword); }else{ if(jCurItem.length <= 0){ jCurItem = jItems.first(); jCurItem.addClass("cur"); keyword = jCurItem.text(); }else{ var index = jCurItem.index(); jCurItem.removeClass("cur"); if(index + 1 >= jItems.length){ keyword = value; }else{ jCurItem = jItems.eq(index+1); jCurItem.addClass("cur"); keyword = jCurItem.text(); } } jthis.val(keyword); } } } } /*event handler*/ $.fn.unintell = function(){ remove(); } $(document).unbind({click:window.intellDocumentClick,keydown:window.intellDocumentKeydown}) .bind({click:window.intellDocumentClick,keydown:window.intellDocumentKeydown}); jthis.focus(function(){ _focusCount++; if(_focusCount > 1){ return; } if(window.intellObj.jthis && jthis !== window.intellObj.jthis){ setIntellObj(null); } var keyword = attrValue(); if(keyword === _dftOpts.defaultValue){ keyword = ""; attrValue(keyword); } if(keyword || _dftOpts.isEmptyRequest){ sendRequest(); } }) jthis.blur(function(){ _focusCount = 0; if(!attrValue()){ attrValue(_dftOpts.defaultValue); } }) jthis.keyup(function(e){ if(e.keyCode === 38 || e.keyCode === 40){ return; } var keyword = attrValue(); if(!keyword){ remove(); window.intellObj.value = _value = ""; return; } if(keyword !== _value){ window.intellObj.value = _value = keyword; sendRequest(); } }); return initBox(); /*function*/ function initBox(){ attrValue(_dftOpts.defaultValue); return jthis; } function initIntell(){ generate(); register(); setIntellObj({jthis:jthis,jResult:jResult}); } function generate(){ var offset = _dftOpts.aligner.offset(); var width = _dftOpts.width ? _dftOpts.width : _dftOpts.aligner.width(); jResult = $("<ul>",{"class":"intellResult"}); jResult.width(width).css({"position":"absolute","left":offset.left,"top":offset.top + jthis.outerHeight()}); $("body").append(jResult); if(_dftOpts.maxHeight > 0){ jResult.height(_dftOpts.maxHeight).css("overflowY","scroll"); } } function remove(){ if(jResult){ jResult.remove(); jResult = null; } } function register(){ jResult.on("click","li",function(){ var jItem = $(this); var index = jItem.index(); var keyword = jItem.text(); attrValue(keyword); _value = keyword; if(_event.itemClick){ _event.itemClick({"jthis":jthis,"jItem":jItem,"item":_cache[index]}); } }).on("mouseenter","li",function(){ $(this).siblings("li").removeClass("cur").end().addClass("cur"); }).on("mouseleave","li",function(){ $(this).removeClass("cur"); }); } function setIntellObj(obj){ if(!obj){ if(window.intellObj.jResult){ window.intellObj.jResult.remove(); } window.intellObj.jthis = null; window.intellObj.jResult = null; }else{ window.intellObj.jthis = obj.jthis; window.intellObj.jResult = obj.jResult; } } function sendRequest(){ var data; if(_event.setData){ data = _event.setData({"jthis":jthis}); } $.ajax({ url:_dftOpts.url, data:data, cache:_ajax.cache, timeout:_ajax.timeout, beforeSend:function(xhr){ if(_event.beforeSend){ _event.beforeSend(xhr); } }, success:function(data){ remove(); showData(data); }, error:null }); } function showData(data){ data = $.trim(data) ? $.parseJSON(data) : data; if(_event.beforeRender){ var rs = _event.beforeRender({"jthis":jthis,"data":data}); if(rs === false){ return; } if(rs !== undefined){ data = rs; } } if(!data){ return; } var jItem,jA,jSpan,hasProp,item,text,otherTexts,isRender,index; var list = $.isArray(data) ? data : [data]; var length = list.length; length = length > _dftOpts.itemNumber ? _dftOpts.itemNumber : list.length; if(length <= 0){ return; } initIntell(); _cache.length = 0; hasProp = list[0][_dftOpts.property]; for(var i=0;i<length;i++){ item = list[i]; if(item === null || item === undefined){ continue; } text = hasProp ? item[_dftOpts.property] : item; text = $.trim(text.toString()); if(text === ""){ continue; } jItem = $("<li>",{"class":"intellResult_item"}); jA = $("<a>",{"title":text}).appendTo(jItem); jSpan = $("<span>").appendTo(jA); index = text.toLowerCase().indexOf(_value.toLowerCase()); otherTexts = splitText(text,_value,index); if(otherTexts){ jSpan.text(text.substr(index,_value.length)); if(otherTexts.length > 1){ $("<b>",{"text":otherTexts[0]}).insertBefore(jSpan); $("<b>",{"text":otherTexts[1]}).insertAfter(jSpan); }else{ if(index === 0){ $("<b>",{"text":otherTexts[0]}).insertAfter(jSpan); }else{ $("<b>",{"text":otherTexts[0]}).insertBefore(jSpan); } } }else{ jSpan.text(text); } isRender = true; if(_event.itemBeforeRender){ isRender = _event.itemBeforeRender({"jthis":jthis,"jItem":jItem,"item":item}); } if(isRender !== false){ jResult.append(jItem); if(_event.itemAfterRender){ _event.itemAfterRender({"jthis":jthis,"jItem":jItem,"item":item}); } } _cache.push(item); } if(_event.endRender){ _event.endRender({"jthis":jthis}); } jResult.show(); } function attrValue(value){ if(!value && value != ""){ return $.trim(jthis.val()); } jthis.val(value); } function splitText(text,value,index){ var tlength = text.length; var vlength = value.length; if(index === -1){ return null; } if(index === 0){ if(index + vlength >= tlength){ return null; } return [text.substr(index + vlength)]; } if(index + vlength >= tlength){ return [text.substr(0,index)]; } return [text.substr(0,index),text.substr(index + vlength)]; } } })(window,jQuery);
樣式
.intellResult{margin:0;padding:0;background:#fff;border:1px solid #b6b6b6;clear:both;z-index:999;display:none;} .intellResult li{margin:0;padding:0;padding:5px 15px;height:20px;line-height:20px;overflow:hidden;text-overflow:ellipsis;cursor:pointer;white-space:nowrap;} .intellResult li.cur{background:#E5E0E0;}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
- javascript和jQuery實(shí)現(xiàn)網(wǎng)頁(yè)實(shí)時(shí)聊天的ajax長(zhǎng)輪詢
- JavaScript/jQuery、HTML、CSS 構(gòu)建 Web IM 遠(yuǎn)程及時(shí)聊天通信程序
- jQuery在vs2008及js文件中的無(wú)智能提示的解決方法
- jquery.cvtooltip.js 基于jquery的氣泡提示插件
- JavaScript實(shí)現(xiàn)離開(kāi)頁(yè)面前提示功能【附j(luò)Query實(shí)現(xiàn)方法】
- Jquery插件分享之氣泡形提示控件grumble.js
- jQuery懸停文字提示框插件jquery.tooltipster.js用法示例【附demo源碼下載】
- jquery.guide.js新版上線操作向?qū)хU空提示jQuery插件(推薦)
- JS(jQuery)實(shí)現(xiàn)聊天接收到消息語(yǔ)言自動(dòng)提醒功能詳解【提示“您有新的消息請(qǐng)注意查收”】
相關(guān)文章
jQuery與javascript對(duì)照學(xué)習(xí) 獲取父子前后元素 實(shí)現(xiàn)代碼
jQuery與javascript對(duì)照學(xué)習(xí)(獲取父子前后元素) ,需要的朋友可以參考下,看看與js有什么不同。2009-10-10一個(gè)可綁定數(shù)據(jù)源的jQuery數(shù)據(jù)表格插件
此文將實(shí)現(xiàn)一個(gè)的jQuery表格插件jQuery.DataGrid。需要的朋友可以參考下。2010-07-07jquery實(shí)現(xiàn)的點(diǎn)擊翻書(shū)效果代碼
這篇文章主要介紹了jquery實(shí)現(xiàn)的點(diǎn)擊翻書(shū)效果代碼,可呈現(xiàn)點(diǎn)擊圖片顯示翻頁(yè)的效果,涉及jQuery響應(yīng)鼠標(biāo)事件動(dòng)態(tài)改變頁(yè)面元素屬性的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11jquery實(shí)現(xiàn)隱藏與顯示動(dòng)畫(huà)效果/輸入框字符動(dòng)態(tài)遞減/導(dǎo)航按鈕切換
jquery實(shí)現(xiàn)隱藏顯示層動(dòng)畫(huà)效果、仿新浪字符動(dòng)態(tài)輸入、tab效果等等,以下為所有代碼,感興趣的朋友可以練練手哈,希望對(duì)大家學(xué)習(xí)有所幫助2013-07-07jQuery EasyUI Dialog拖不下來(lái)如何解決
這篇文章主要介紹了jQuery EasyUI Dialog拖不下來(lái)到底如何解決,遇到這類問(wèn)題的,或者是感興趣的小朋友可以參考一下2015-09-09修改jQuery Validation里默認(rèn)的驗(yàn)證方法
在最近做的一個(gè)項(xiàng)目中,使用jQuery Validation驗(yàn)證日期,遇到的問(wèn)題和一個(gè)沒(méi)有預(yù)料到的情況是,在ASP.NET MVC 3的項(xiàng)目中,對(duì)于 input type="date" data-val="true"的元素,如果調(diào)用form的valid方法驗(yàn)證form,雖然我沒(méi)有添加日期驗(yàn)證的設(shè)置2012-02-02jQuery實(shí)現(xiàn)點(diǎn)擊下拉框中的值累加到文本框中的方法示例
這篇文章主要介紹了jQuery實(shí)現(xiàn)點(diǎn)擊下拉框中的值累加到文本框中的方法,涉及jQuery事件綁定及頁(yè)面元素屬性動(dòng)態(tài)獲取與操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-10-10使用jquery.validate自定義方法實(shí)現(xiàn)"手機(jī)號(hào)碼或者固話至少填寫(xiě)一個(gè)"的邏輯驗(yàn)證
這篇文章主要介紹了使用jquery.validate自定義方法實(shí)現(xiàn)"手機(jī)號(hào)碼或者固定電話"的邏輯驗(yàn)證,解決了手機(jī)號(hào)碼或者固定電話字至少填寫(xiě)一個(gè)的驗(yàn)證問(wèn)題,分享給大家2014-09-09通過(guò)JQuery將DIV的滾動(dòng)條滾動(dòng)到指定的位置方便自動(dòng)定位
本文為大家介紹下將DIV的滾動(dòng)條滾動(dòng)到其子元素所在的位置,方便自動(dòng)定位,需要的朋友可以參考下2014-05-05