基于jquery實(shí)現(xiàn)智能提示控件intellSeach.js
一、需求
我們經(jīng)常會(huì)遇到【站內(nèi)搜索】的需求,為了提高用戶體驗(yàn),我們希望能做到像百度那樣的即時(shí)智能提示。例如:某公司人事管理系統(tǒng),想搜索李XX,只要輸入“李”,系統(tǒng)自然會(huì)提示一些姓李的員工,這樣方便用戶使用。說白了,就是用戶邊輸入,系統(tǒng)會(huì)提示相關(guān)的結(jié)果;或者,當(dāng)用戶點(diǎn)擊搜索框時(shí),就推薦一些內(nèi)容,如360、百度都會(huì)提示今天的主要新聞或搜索量大的內(nèi)容。
jquery 已經(jīng)有一個(gè)這樣的插件了,叫 autocomplete, 但我覺得不好用。關(guān)于autocomplete的介紹也很多,有興趣的朋友可以去試試。
看標(biāo)題就知道,這里只是分享一個(gè)插件,不會(huì)討論后臺(tái)搜索的相關(guān)算法和過程,也就是說,后臺(tái)返回特定格式的數(shù)據(jù),控件負(fù)責(zé)渲染結(jié)果呈現(xiàn)。ok,先看一下效果圖:
樣式與控件無關(guān),只需要一個(gè) input text 就可以了。
二、參數(shù)說明
控件以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,通過點(diǎn)擊事件即可。
itemNumber: 顯示的項(xiàng)數(shù)目。
isEmptyRequest: focus時(shí),空白是否發(fā)起請(qǐng)求。就像前面說的,如果點(diǎn)擊搜索框時(shí)(此時(shí)沒有內(nèi)容),想要推薦一些內(nèi)容,設(shè)置該屬性為true,即會(huì)發(fā)起請(qǐng)求。
defaultValue: 默認(rèn)值。通常會(huì)是:“請(qǐng)輸入關(guān)鍵詞...” 這類的提示。
width: 下拉列表寬度。
aligner: 要對(duì)齊的元素。
maxHeight: 最大高度。如果設(shè)置該高度,超過時(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è)屬性,某些情況如果沒有該屬性的,則為空。包括如下屬性:
jthis: input 的 jQuery 對(duì)象。
jItem: 項(xiàng)的 jQuery 對(duì)象。
data: 返回的 json 字符串。如果在前臺(tái)需要對(duì)返回 json 再進(jìn)行處理,那么可以通過 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("沒有當(dāng)前項(xiàng)");
}
}
}
});
四、總結(jié)
如果你還有自己的邏輯需要處理,也支持鏈?zhǔn)秸{(diào)用,大可以這樣寫 $("#search").intellSearch({參數(shù)...}).focus(function(){你的處理...});
分享該插件希望能幫助到有需要的朋友,主要用于學(xué)習(xí)。由于是v1.0,可能還有一些bug,有發(fā)現(xiàn)的朋友也可以告訴我,我會(huì)及時(shí)修正。
附源代碼
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ù)說明: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)頁實(shí)時(shí)聊天的ajax長(zhǎng)輪詢
- JavaScript/jQuery、HTML、CSS 構(gòu)建 Web IM 遠(yuǎn)程及時(shí)聊天通信程序
- jQuery在vs2008及js文件中的無智能提示的解決方法
- jquery.cvtooltip.js 基于jquery的氣泡提示插件
- JavaScript實(shí)現(xiàn)離開頁面前提示功能【附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)聊天接收到消息語言自動(dòng)提醒功能詳解【提示“您有新的消息請(qǐng)注意查收”】
相關(guān)文章
jquery自定義插件——window的實(shí)現(xiàn)【示例代碼】
下面小編就為大家?guī)硪黄猨query自定義插件——window的實(shí)現(xiàn)【示例代碼】。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考2016-05-05
Jquery replace 字符替換實(shí)現(xiàn)代碼
Jquery replace 字符替換實(shí)現(xiàn)代碼,需要的朋友可以參考下。2010-12-12
淺析Js(Jquery)中,字符串與JSON格式互相轉(zhuǎn)換的示例(直接運(yùn)行實(shí)例)
這幾天,遇到了json格式在JS和Jquey的環(huán)境中,需要相互轉(zhuǎn)換,在網(wǎng)上查了一下,大多為缺胳膊少腿,也許咱是菜鳥吧,終于測(cè)試成功后,還是給初學(xué)者們一個(gè)實(shí)例吧2013-07-07
JQueryEasyUI之DataGrid數(shù)據(jù)顯示
在有的項(xiàng)目中,為了方便將數(shù)據(jù)庫中的某些定值儲(chǔ)存為指定的數(shù)字,怎么處理這種問題呢?下面小編通過一段代碼給大家介紹下,需要的朋友參考下2016-11-11
實(shí)現(xiàn)音樂播放器的代碼(html5+css3+jquery)
這篇文章主要講實(shí)現(xiàn)音樂播放器的代碼(html5+css3+jquery),需要的朋友可以參考下2015-08-08
jquery 正整數(shù)數(shù)字校驗(yàn)正則表達(dá)式
本文主要介紹了jquery正整數(shù)數(shù)字校驗(yàn)正則表達(dá)式的方法。具有一定的參考價(jià)值,下面跟著小編一起來看下吧2017-01-01
jQuery實(shí)現(xiàn)簡(jiǎn)單彈窗遮罩效果
本文主要介紹了jquery實(shí)現(xiàn)簡(jiǎn)單彈窗遮罩效果的實(shí)例,具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-02-02
基于jquery的一個(gè)簡(jiǎn)單的腳本驗(yàn)證插件
基于jquery的一個(gè)簡(jiǎn)單的腳本驗(yàn)證插件,希望能對(duì)大家有所幫助,有demo2010-04-04

