您的位置:首页 > Web前端 > JavaScript

编写简易的JS输入框模糊查询匹配(附有源码和demo)

2013-11-21 00:34 671 查看
前言:JS输入框模糊匹配插件以前在工作写过一个类似的 所以这次写轻松很多,这次写优化了几个方面:

1. 添加动态加载css文件 不需要引入css css全部在JS动态生成。

2. 不需要额外的标签 只需要一个input输入框 并且默认指定一个class类名为 "inputElem" 当然也可以自己配置参数 还需要一个当前父级容器增加一个默认类名 parentCls(也可以自己配置),因为输入框匹配值后需要一个隐藏域 所以需要隐藏域增加一个class "hiddenCls" 当然也支持自己配置参数。

如下代码:

/**
* JS 模糊查询
* @author tugenhua
* @date 2013-11-19
* @param 1.当前的input add targetCls
* 2. 隐藏域里面统一增加同类名 叫 hiddenCls
* 3. 在各个父级元素上 添加类名 parentCls
*/

function AutoComplete (options) {
this.config = {
targetCls          : '.inputElem',          // 输入框目标元素
parentCls          : '.parentCls',          // 父级类
hiddenCls          : '.hiddenCls',          // 隐藏域input
searchForm         :'.jqtransformdone',     //form表单
hoverBg            : 'hoverBg',             // 鼠标移上去的背景
outBg              : 'outBg',               // 鼠标移下拉的背景
isSelectHide       : true,                 // 点击下拉框 是否隐藏
url                : '',                    // url接口
height             : 0,                     // 默认为0 不设置的话 那么高度自适应
manySelect         : false,                 // 输入框是否多选 默认false 单选
renderHTMLCallback : null,                  // keyup时 渲染数据后的回调函数
callback           : null,                  // 点击某一项 提供回调
closedCallback     : null                   // 点击输入框某一项x按钮时 回调函数
};

this.cache = {
currentIndex        : -1,
oldIndex            : -1,
inputArrs           : []                 // 多选时候 输入框值放到数组里面去
};
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;

// 鼠标点击输入框时候
$(_config.targetCls).each(function(index,item) {

// 点击搜索回来后判断 隐藏域有没有值

$(item).click(function(){
var callVal = $.trim($(this).val()),
curP = $(this).closest(_config.parentCls),
hiddenVal = $.trim($(_config.hiddenCls,curP).val()),
targetParent = $(this).parent();
if(callVal != '' && hiddenVal != '') {
self._createDiv(targetParent,callVal);
!$(this).hasClass('hidden') && $(this).addClass('hidden');
self._hover();
self._closed();
}
});

/*
*  禁止 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) {
// 初始化时候 动态创建下拉框容器
$(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','overflow':'hidden'});
}

var curIndex = self._keyCode(keyCode);
if(curIndex > -1){
self._keyUpAndDown(targetVal,e,targetParent);
}else {
var isHasClass = _config.targetCls.replace(/^\./,'');

if(targetVal != '' && $(this).hasClass(isHasClass)) {
self._doPostAction(targetVal,targetParent);
}

}
});

// 失去焦点时 如果没有点击 或者上下移时候 直接输入 那么当前输入框值情况 隐藏域值情况
$(item).blur(function(e){
var target = e.target,
targetParent = $(target).closest(_config.parentCls),
hiddenVal = $(_config.hiddenCls,targetParent).val();

if($(this).attr('up') || $(this).attr('down') || hiddenVal != '') {
return;
}else {
$(this).val('');
$(_config.hiddenCls,targetParent).val('');
}
});
});

// 阻止form表单默认enter键提交
$(_config.searchForm).each(function(index,item) {
$(item).keydown(function(e){
var keyCode = e.keyCode;
if(keyCode == 13) {
return false;
}
});
});

// 点击文档
$(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 !important;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;padding-left:3px;height:24px;line-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 0px 0 3px;margin-top:1px;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;

// 如果请求成功后 返回了数据(根据元素的长度来判断) 执行以下操作
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);
// 上移操作增加一个属性 当失去焦点时候 判断有没有这个属性
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);
// 下移操作增加一个属性 当失去焦点时候 判断有没有这个属性
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');

if($(_config.targetCls,targetParent).attr('up') || $(_config.targetCls,targetParent).attr('down')) {
$(_config.targetCls,targetParent).val(curVal);
if(_config.isSelectHide) {
!$(".auto-tips",targetParent).hasClass('hidden') && $(".auto-tips",targetParent).addClass('hidden');
!$(_config.targetCls,targetParent).hasClass('hidden') && $(_config.targetCls,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;
$.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+'" 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();

// 出现滚动条 计算p的长度 * 一项p的高度 是否大于 设置的高度 如是的话 出现滚动条 反之
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'});
}
}
},
/**
* 当数据相同的时 点击对应的项时 返回数据
*/
_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);
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();
});

// 鼠标移上效果
$('.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({'padding-left':'3px'});
},function(){

});
$('.create-input .alink',targetParent).hover(function(){
$(this).css({'color':'#D96500'});
},function(){
$(this).css({'color':''});
});
},
// 动态的创建div标签 遮住input输入框
_createDiv: function(targetParent,dataAttr){
var self = this,
_config = self.config;
var iscreate = $('.create-input',targetParent);

// 确保只创建一次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'});
var parentWidth = $(targetParent).outerWidth(),
parentheight = $(targetParent).outerHeight(),
iwidth = $('.create-input i',targetParent).outerWidth(),
closedWidth = $('.create-input .alink').outerWidth();
if(iwidth >= parentWidth - closedWidth - 3) {
$('.create-input span i',targetParent).css({'width':(parentWidth - closedWidth - 3)+'px','overflow':'hidden','float':'left','height':parentheight});
}

},
// X 关闭事件
_closed: function(targetParent){
var self = this,
_config = self.config;
/*
* 点击X 关闭按钮
* 判断当前输入框有没有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();
});
},
/*
* 数组去重复
*/
_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 动态添加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);
}

// 仅添加一次,不重复添加
if (elem) {
return;
}

//elem = $('<style></style>'); 不能这样创建 IE8有bug
elem =  document.createElement("style");

// 先添加到 DOM 树中,再给 cssText 赋值,否则 css hack 会失效
$('head', doc).append(elem);

if (elem.styleSheet) { // IE
elem.styleSheet.cssText = cssText;
} else { // W3C
$(elem).append(doc.createTextNode(cssText));
}
},
/*
* 销毁操作 释放内存
*/
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'
});
});


View Code
JS输入框模糊匹配下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: