JS仿百度搜索自動(dòng)提示框匹配查詢功能
1. 添加動(dòng)態(tài)加載css文件 不需要引入css css全部在JS動(dòng)態(tài)生成。
2. 不需要額外的標(biāo)簽 只需要一個(gè)input輸入框 并且默認(rèn)指定一個(gè)class類名為 "inputElem" 當(dāng)然也可以自己配置參數(shù) 還需要一個(gè)當(dāng)前父級(jí)容器增加一個(gè)默認(rèn)類名 parentCls(也可以自己配置),因?yàn)檩斎肟蚱ヅ渲岛笮枰粋€(gè)隱藏域 所以需要隱藏域增加一個(gè)class "hiddenCls" 當(dāng)然也支持自己配置參數(shù)。
如下代碼:
<div class="parentCls">
<div style="width:200px;height:26px;border:1px solid #ccc;">
<input type="text" class="inputElem" style="width:200px;height:26px;line-height:26px;"/>
</div>
<input type="hidden" class="hiddenCls"/>
</div>
<div class="parentCls">
<div style="width:200px;height:26px;border:1px solid #ccc;">
<input type="text" class="inputElem" style="width:200px;height:26px;line-height:26px;"/>
</div>
<input type="hidden" class="hiddenCls"/>
</div>
3. 支持頁(yè)面上有多個(gè)輸入框。
4. 支持鼠標(biāo)點(diǎn)擊和 鍵盤 上移和下移鍵操作 類似于百度輸入框。
頁(yè)面上所有的標(biāo)簽都是動(dòng)態(tài)的生成的,不需要額外的標(biāo)簽。如上面的 只需要input標(biāo)簽 其他的div標(biāo)簽不依賴 只需要父級(jí)元素增加class "parentCls"(當(dāng)然可以自己配置類名),
及要傳給后臺(tái)開(kāi)發(fā)人員的隱藏域輸入框 增加一個(gè)class "hiddenCls" 當(dāng)然也可以自動(dòng)配置參數(shù)。
我的模糊查詢匹配的需求是這樣的:
1. 每keyup時(shí)候 點(diǎn)擊或者鍵盤上移下移操作 輸入框填充用戶名/工號(hào) 隱藏域填充工號(hào) 發(fā)請(qǐng)求 服務(wù)器返回?cái)?shù)據(jù) 渲染出來(lái)。當(dāng)然 隱藏域填充工號(hào) 值是form表單提交時(shí)候 后臺(tái)要拿到提交過(guò)來(lái)的工號(hào) 所以需要這么一個(gè)隱藏域。
2. 當(dāng)用戶直接在輸入框輸入值時(shí)候 并沒(méi)有鍵盤上移下移 或者 點(diǎn)擊下拉框某一項(xiàng)時(shí)候 當(dāng)鼠標(biāo)失去焦點(diǎn)時(shí)候(blur) 當(dāng)前輸入框值為空 隱藏域值為空,這樣做的目的 是為了防止上次form提交過(guò)后的數(shù)據(jù)仍然保存在隱藏域里面 當(dāng)用戶重新輸入的時(shí)候 用戶也并沒(méi)有操作鍵盤上下移操作或者點(diǎn)擊操作 再點(diǎn)擊提交按鈕時(shí)(失去焦點(diǎn)),那么值為空 隱藏域值為空 這樣防止搜索出來(lái)不是用戶輸入的那個(gè)東東。
3. 當(dāng)用戶點(diǎn)擊某一項(xiàng)時(shí)候 或者 上移下移時(shí)候 輸入框動(dòng)態(tài)的生成值 且輸入框值現(xiàn)在不能重新輸入 只有當(dāng)點(diǎn)擊輸入框x的時(shí)候 才可以重新輸入。
4. 已經(jīng)遺留輸入框可以多選的接口 目前還未完善輸入框多選的操作。
5. 禁止ctrl+v 或者右鍵 粘貼操作。
下面HTML代碼如下:
<div class="parentCls">
<div style="width:200px;height:26px;border:1px solid #ccc;">
<input type="text" class="inputElem" style="width:200px;height:26px;line-height:26px;"/>
</div>
<input type="hidden" class="hiddenCls"/>
</div>
<div class="parentCls">
<div style="width:200px;height:26px;border:1px solid #ccc;">
<input type="text" class="inputElem" style="width:200px;height:26px;line-height:26px;"/>
</div>
<input type="hidden" class="hiddenCls"/>
</div>
<input type="button" value="提交"/>
JS代碼如下:
/**
* JS 模糊查詢
* @author tugenhua
* @date 2013-11-19
* @param 1.當(dāng)前的input add targetCls
* 2. 隱藏域里面統(tǒng)一增加同類名 叫 hiddenCls
* 3. 在各個(gè)父級(jí)元素上 添加類名 parentCls
*/
function AutoComplete (options) {
this.config = {
targetCls : '.inputElem', // 輸入框目標(biāo)元素
parentCls : '.parentCls', // 父級(jí)類
hiddenCls : '.hiddenCls', // 隱藏域input
searchForm :'.jqtransformdone', //form表單
hoverBg : 'hoverBg', // 鼠標(biāo)移上去的背景
outBg : 'outBg', // 鼠標(biāo)移下拉的背景
isSelectHide : true, // 點(diǎn)擊下拉框 是否隱藏
url : '', // url接口
height : 0, // 默認(rèn)為0 不設(shè)置的話 那么高度自適應(yīng)
manySelect : false, // 輸入框是否多選 默認(rèn)false 單選
renderHTMLCallback : null, // keyup時(shí) 渲染數(shù)據(jù)后的回調(diào)函數(shù)
callback : null, // 點(diǎn)擊某一項(xiàng) 提供回調(diào)
closedCallback : null // 點(diǎn)擊輸入框某一項(xiàng)x按鈕時(shí) 回調(diào)函數(shù)
};
this.cache = {
currentIndex : -1,
oldIndex : -1,
inputArrs : [] // 多選時(shí)候 輸入框值放到數(shù)組里面去
};
this.init(options);
}
AutoComplete.prototype = {
constructor: AutoComplete,
init: function(options) {
this.config = $.extend(this.config, options || {});
var self = this,
_config = self.config,
_cache = self.cache;
// 鼠標(biāo)點(diǎn)擊輸入框時(shí)候
$(_config.targetCls).each(function(index,item) {
/*
* 禁止 ctrl+v 和 黏貼事件
*/
$(item).unbind('paste');
$(item).bind('paste',function(e){
e.preventDefault();
var target = e.target,
targetParent = $(target).closest(_config.parentCls);
$(this).val('');
$(_config.hiddenCls,targetParent) && $(_config.hiddenCls,targetParent).val('');
});
$(item).keyup(function(e){
_cache.inputArrs = [];
var targetVal = $.trim($(this).val()),
keyCode = e.keyCode,
elemHeight = $(this).outerHeight(),
elemWidth = $(this).outerWidth();
// 如果輸入框值為空的話 那么隱藏域的value清空掉
if(targetVal == '') {
var curParents = $(this).closest(_config.parentCls);
$(_config.hiddenCls,curParents).val('');
}
var targetParent = $(this).parent();
$(targetParent).css({'position':'relative'});
if($('.auto-tips',targetParent).length == 0) {
// 初始化時(shí)候 動(dòng)態(tài)創(chuàng)建下拉框容器
$(targetParent).append($('<div class="auto-tips hidden"></div>'));
$('.auto-tips',targetParent).css({'position':'absolute','top':elemHeight,'left':'0px','z-index':999,'width':elemWidth,'border':'1px solid #ccc'});
}
var curIndex = self._keyCode(keyCode);
if(curIndex > -1){
self._keyUpAndDown(targetVal,e,targetParent);
}else {
if(targetVal != '') {
self._doPostAction(targetVal,targetParent);
}
}
});
// 失去焦點(diǎn)時(shí) 如果沒(méi)有點(diǎn)擊 或者上下移時(shí)候 直接輸入 那么當(dāng)前輸入框值情況 隱藏域值情況
$(item).blur(function(e){
var target = e.target,
targetParent = $(target).closest(_config.parentCls);
if($(this).attr('up') || $(this).attr('down')) {
return;
}else {
$(this).val('');
$(_config.hiddenCls,targetParent).val('');
}
});
});
// 阻止form表單默認(rèn)enter鍵提交
$(_config.searchForm).each(function(index,item) {
$(item).keydown(function(e){
var keyCode = e.keyCode;
if(keyCode == 13) {
return false;
}
});
});
// 點(diǎn)擊文檔
$(document).click(function(e){
e.stopPropagation();
var target = e.target,
tagParent = $(target).parent(),
attr = $(target,tagParent).closest('.auto-tips');
var tagCls = _config.targetCls.replace(/^\./,'');
if(attr.length > 0 || $(target,tagParent).hasClass(tagCls)) {
return;
}else {
$('.auto-tips').each(function(index,item){
!$(item,tagParent).hasClass('hidden') && $(item,tagParent).addClass('hidden');
});
}
});
var stylesheet = '.auto-tips { margin: 0 1px; list-style: none;height:auto !important;padding: 0px;position:absolute; border:1px solid #ccc; top:27px; left:0; z-index:999; width:100%;background:#fff !important;}' +
'.auto-tips p {overflow: hidden;margin: 1px 0;padding: 5px 5px;border-bottom: 1px solid #e7e7e7;color: #666;text-decoration: none;line-height: 23px;white-space: nowrap;cursor: pointer;zoom: 1;}' +
'.auto-tips p img{ vertical-align:middle;float:left;}' +
'.create-input{line-height:26px,padding-left:3px;}' +
'.create-input span{margin-top:1px;height:24px;float:left;}' +
'.create-input span i,.auto-tips span a{font-style:normal;float:left;cursor:default;}' +
'.create-input span a{padding:0 8px 0 3px;cursor:pointer;}' +
'.auto-tips p.hoverBg {background-color: #669cb6;color: #fff;cursor: pointer;}' +
'.hidden {display:none;}';
this._addStyleSheet(stylesheet);
},
/**
* 鍵盤上下鍵操作
*/
_keyUpAndDown: function(targetVal,e,targetParent) {
var self = this,
_cache = self.cache,
_config = self.config;
// 如果請(qǐng)求成功后 返回了數(shù)據(jù)(根據(jù)元素的長(zhǎng)度來(lái)判斷) 執(zhí)行以下操作
if($('.auto-tips p',targetParent) && $('.auto-tips p',targetParent).length > 0) {
var plen = $('.auto-tips p',targetParent).length,
keyCode = e.keyCode;
_cache.oldIndex = _cache.currentIndex;
// 上移操作
if(keyCode == 38) {
if(_cache.currentIndex == -1) {
_cache.currentIndex = plen - 1;
}else {
_cache.currentIndex = _cache.currentIndex - 1;
if(_cache.currentIndex < 0) {
_cache.currentIndex = plen - 1;
}
}
if(_cache.currentIndex !== -1) {
!$('.auto-tips .p-index'+_cache.currentIndex,targetParent).hasClass(_config.hoverBg) &&
$('.auto-tips .p-index'+_cache.currentIndex,targetParent).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
var curAttr = $('.auto-tips .p-index'+_cache.currentIndex,targetParent).attr('data-html'),
embId = $('.auto-tips .p-index'+_cache.currentIndex,targetParent).attr('embId');
// 判斷是否是多選操作 多選操作 暫留接口
if(_config.manySelect) {
_cache.inputArrs.push(curAttr);
_cache.inputArrs = self._unique(_cache.inputArrs);
self._manySelect(targetParent);
}else {
$(_config.targetCls,targetParent).val(curAttr);
// 上移操作增加一個(gè)屬性 當(dāng)失去焦點(diǎn)時(shí)候 判斷有沒(méi)有這個(gè)屬性
if(!$(_config.targetCls,targetParent).attr('up')){
$(_config.targetCls,targetParent).attr('up','true');
}
var pCls = $(_config.targetCls,targetParent).closest(_config.parentCls);
$(_config.hiddenCls,pCls).val(embId);
self._createDiv(targetParent,curAttr);
self._closed(targetParent);
// hover
self._hover(targetParent);
}
}
}else if(keyCode == 40) { //下移操作
if(_cache.currentIndex == plen - 1) {
_cache.currentIndex = 0;
}else {
_cache.currentIndex++;
if(_cache.currentIndex > plen - 1) {
_cache.currentIndex = 0;
}
}
if(_cache.currentIndex !== -1) {
!$('.auto-tips .p-index'+_cache.currentIndex,targetParent).hasClass(_config.hoverBg) &&
$('.auto-tips .p-index'+_cache.currentIndex,targetParent).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
var curAttr = $('.auto-tips .p-index'+_cache.currentIndex,targetParent).attr('data-html'),
embId = $('.auto-tips .p-index'+_cache.currentIndex,targetParent).attr('embId');
// 判斷是否是多選操作 多選操作 暫留接口
if(_config.manySelect) {
_cache.inputArrs.push(curAttr);
_cache.inputArrs = self._unique(_cache.inputArrs);
self._manySelect(targetParent);
}else {
$(_config.targetCls,targetParent).val(curAttr);
// 下移操作增加一個(gè)屬性 當(dāng)失去焦點(diǎn)時(shí)候 判斷有沒(méi)有這個(gè)屬性
if(!$(_config.targetCls,targetParent).attr('down')){
$(_config.targetCls,targetParent).attr('down','true');
}
var pCls = $(_config.targetCls,targetParent).closest(_config.parentCls);
$(_config.hiddenCls,pCls).val(embId);
self._createDiv(targetParent,curAttr);
self._closed(targetParent);
// hover
self._hover(targetParent);
}
}
}else if(keyCode == 13) { //回車操作
var curVal = $('.auto-tips .p-index'+_cache.oldIndex,targetParent).attr('data-html');
$(_config.targetCls,targetParent).val(curVal);
if(_config.isSelectHide) {
!$(".auto-tips",targetParent).hasClass('hidden') && $(".auto-tips",targetParent).addClass('hidden');
}
_cache.currentIndex = -1;
_cache.oldIndex = -1;
}
}
},
// 鍵碼判斷
_keyCode: function(code) {
var arrs = ['17','18','38','40','37','39','33','34','35','46','36','13','45','44','145','19','20','9'];
for(var i = 0, ilen = arrs.length; i < ilen; i++) {
if(code == arrs[i]) {
return i;
}
}
return -1;
},
_doPostAction: function(targetVal,targetParent) {
var self = this,
_cache = self.cache,
_config = self.config,
url = _config.url;
// 假如返回的數(shù)據(jù)如下:
var results = [{lastName:'tugenhua',emplId:'E0987',image:''},{lastName:'tugenhua',emplId:'E0988',image:''},{lastName:'tugenhua',emplId:'E0989',image:''}];
self._renderHTML(results,targetParent);
self._executeClick(results,targetParent);
/** $.get(url+"?keyword="+targetVal+"×tamp="+new Date().getTime(),function(data){
var ret = $.parseJSON(data.content),
results = ret.results;
if(results.length > 0) {
self._renderHTML(results,targetParent);
self._executeClick(results,targetParent);
}else {
!$('.auto-tips',targetParent).hasClass('hidden') && $('.auto-tips',targetParent).addClass("hidden");
$('.auto-tips',targetParent).html('');
}
});**/
},
_renderHTML: function(ret,targetParent) {
var self = this,
_config = self.config,
_cache = self.cache,
html = '';
for(var i = 0, ilen = ret.length; i < ilen; i+=1) {
html += '<p data-html = "'+ret[i].lastName+'('+ret[i].emplId+')" embId="'+ret[i].emplId+'" class="p-index'+i+'">' +
'<img src="'+ret[i].image+'" style="margin-right:5px;" height="25" width="25" title="" alt="">' +
'<span>'+ret[i].lastName+'('+ret[i].emplId+')</span>' +
'</p>';
}
// 渲染值到下拉框里面去
$('.auto-tips',targetParent).html(html);
$('.auto-tips',targetParent).hasClass('hidden') && $('.auto-tips',targetParent).removeClass('hidden');
$('.auto-tips p:last',targetParent).css({"border-bottom":'none'});
_config.renderHTMLCallback && $.isFunction(_config.renderHTMLCallback) && _config.renderHTMLCallback();
// 出現(xiàn)滾動(dòng)條 計(jì)算p的長(zhǎng)度 * 一項(xiàng)p的高度 是否大于 設(shè)置的高度 如是的話 出現(xiàn)滾動(dòng)條 反之
var plen = $('.auto-tips p',targetParent).length,
pheight = $('.auto-tips p',targetParent).height();
if(_config.height > 0) {
if(plen*pheight > _config.height) {
$('.auto-tips',targetParent).css({'height':_config.height,'overflow':'auto'});
}else {
$('.auto-tips',targetParent).css({'height':'auto','overflow':'auto'});
}
}
},
/**
* 當(dāng)數(shù)據(jù)相同的時(shí) 點(diǎn)擊對(duì)應(yīng)的項(xiàng)時(shí) 返回?cái)?shù)據(jù)
*/
_executeClick: function(ret,targetParent) {
var self = this,
_config = self.config,
_cache = self.cache;
$('.auto-tips p',targetParent).unbind('click');
$('.auto-tips p',targetParent).bind('click',function(e){
var dataAttr = $(this).attr('data-html'),
embId = $(this).attr('embId');
// 判斷是否多選
if(_config.manySelect) {
_cache.inputArrs.push(dataAttr);
_cache.inputArrs = self._unique(_cache.inputArrs);
self._manySelect(targetParent);
}else {
$(_config.targetCls,targetParent).val(dataAttr);
var parentCls = $(_config.targetCls,targetParent).closest(_config.parentCls),
hiddenCls = $(_config.hiddenCls,parentCls);
$(hiddenCls).val(embId);
self._createDiv(targetParent,dataAttr);
// hover
self._hover(targetParent);
!$(_config.targetCls,targetParent).hasClass('hidden') && $(_config.targetCls,targetParent).addClass('hidden');
}
self._closed(targetParent);
if(_config.isSelectHide) {
!$('.auto-tips',targetParent).hasClass('hidden') && $('.auto-tips',targetParent).addClass('hidden');
}
_config.callback && $.isFunction(_config.callback) && _config.callback();
});
// 鼠標(biāo)移上效果
$('.auto-tips p',targetParent).hover(function(e){
!$(this,targetParent).hasClass(_config.hoverBg) &&
$(this,targetParent).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
});
},
_hover: function(targetParent){
$('.create-input span',targetParent).hover(function(){
$(this).css({"background":'#ccc','padding-left':'0px'});
},function(){
$(this).css({"background":''});
});
},
// 動(dòng)態(tài)的創(chuàng)建div標(biāo)簽 遮住input輸入框
_createDiv: function(targetParent,dataAttr){
var self = this,
_config = self.config;
var iscreate = $('.create-input',targetParent);
// 確保只創(chuàng)建一次div
if(iscreate.length > 0) {
$('.create-input',targetParent).remove();
}
$(targetParent).prepend($('<div class="create-input"><span><i></i></span></div>'));
$('.create-input span i',targetParent).html(dataAttr);
$(_config.targetCls,targetParent).val(dataAttr);
$('.create-input span',targetParent).append('<a class="alink">X</a>');
$('.alink',targetParent).css({'float':'left','background':'none'});
},
// X 關(guān)閉事件
_closed: function(targetParent){
var self = this,
_config = self.config;
/*
* 點(diǎn)擊X 關(guān)閉按鈕
* 判斷當(dāng)前輸入框有沒(méi)有up和down屬性 有的話 刪除掉 否則 什么都不做
*/
$('.alink',targetParent).click(function(){
$('.create-input',targetParent) && $('.create-input',targetParent).remove();
$(_config.targetCls,targetParent) && $(_config.targetCls,targetParent).hasClass('hidden') &&
$(_config.targetCls,targetParent).removeClass('hidden');
$(_config.targetCls,targetParent).val('');
//清空隱藏域的值
var curParent = $(_config.targetCls,targetParent).closest(_config.parentCls);
$(_config.hiddenCls,curParent).val('');
var targetInput = $(_config.targetCls,targetParent);
if($(targetInput).attr('up') || $(targetInput).attr('down')) {
$(targetInput).attr('up') && $(targetInput).removeAttr('up');
$(targetInput).attr('down') && $(targetInput).removeAttr('down');
}
_config.closedCallback && $.isFunction(_config.closedCallback) && _config.closedCallback();
});
},
/*
* 數(shù)組去重復(fù)
*/
_unique: function(arrs) {
var obj = {},
newArrs = [];
for(var i = 0, ilen = arrs.length; i < ilen; i++) {
if(obj[arrs[i]] != 1) {
newArrs.push(arrs[i]);
obj[arrs[i]] = 1;
}
}
return newArrs;
},
/*
* 輸入框多選操作
*/
_manySelect: function(targetParent) {
var self = this,
_config = self.config,
_cache = self.cache;
if(_cache.inputArrs.length > 0) {
$(_config.targetCls,targetParent).val(_cache.inputArrs.join(','));
}
},
/*
* 判斷是否是string
*/
_isString: function(str) {
return Object.prototype.toString.apply(str) === '[object String]';
},
/*
* JS 動(dòng)態(tài)添加css樣式
*/
_addStyleSheet: function(refWin, cssText, id){
var self = this;
if(self._isString(refWin)) {
id = cssText;
cssText = refWin;
refWin = window;
}
refWin = $(refWin);
var doc = document;
var elem;
if (id && (id = id.replace('#', ''))) {
elem = $('#' + id, doc);
}
// 僅添加一次,不重復(fù)添加
if (elem) {
return;
}
//elem = $('<style></style>'); 不能這樣創(chuàng)建 IE8有bug
elem = document.createElement("style");
// 先添加到 DOM 樹(shù)中,再給 cssText 賦值,否則 css hack 會(huì)失效
$('head', doc).append(elem);
if (elem.styleSheet) { // IE
elem.styleSheet.cssText = cssText;
} else { // W3C
elem.appendChild(doc.createTextNode(cssText));
}
},
/*
* 銷毀操作 釋放內(nèi)存
*/
destory: function() {
var self = this,
_config = self.config,
_cache = self.cache;
_cache.ret = [];
_cache.currentIndex = 0;
_cache.oldIndex = 0;
_cache.inputArrs = [];
_config.targetCls = null;
}
};
// 初始化
$(function(){
var auto = new AutoComplete({
// url: '/rocky/commonservice/user/find.json'
});
});
- JS組件Bootstrap實(shí)現(xiàn)彈出框和提示框效果代碼
- JavaScript中通過(guò)提示框跳轉(zhuǎn)頁(yè)面的方法
- js彈出框、對(duì)話框、提示框、彈窗實(shí)現(xiàn)方法總結(jié)(推薦)
- JavaScript基礎(chǔ)教程之a(chǎn)lert彈出提示框?qū)嵗?/a>
- PHP 實(shí)現(xiàn)類似js中alert() 提示框
- 修改js confirm alert 提示框文字的簡(jiǎn)單實(shí)例
- JS實(shí)現(xiàn)關(guān)閉當(dāng)前頁(yè)而不彈出提示框的方法
- JS+CSS實(shí)現(xiàn)一個(gè)氣泡提示框
- JS實(shí)時(shí)彈出新消息提示框并有提示音響起的實(shí)現(xiàn)代碼
- 原生js實(shí)現(xiàn)自定義消息提示框
相關(guān)文章
Javascript根據(jù)指定下標(biāo)或?qū)ο髣h除數(shù)組元素
刪除數(shù)組元素在工作中經(jīng)常會(huì)用到,本文講解一下Javascript根據(jù)下標(biāo)刪除數(shù)組元素的方法,需要了解的朋友可以參考下2012-12-12教你JavaScript利用charAt()統(tǒng)計(jì)出現(xiàn)次數(shù)最多的字符和次數(shù)
這篇文章主要介紹了JavaScript利用charAt()統(tǒng)計(jì)出現(xiàn)次數(shù)最多的字符和次數(shù)的操作方法,本文以判斷一個(gè)字符串'aabcdobdackoppz'中出現(xiàn)次數(shù)最多的字符,并統(tǒng)計(jì)其次數(shù)為例,通過(guò)實(shí)例代碼給大家詳細(xì)介紹,需要的朋友參考下吧2021-08-08探索JavaScript中私有成員的相關(guān)知識(shí)
這篇文章主要介紹了探索JavaScript中私有成員的相關(guān)知識(shí),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下2019-06-06