JS代码:
(function ($) {
/**
* autor: Squeen
* email: chuxue1342@qq.com
* site: http://blog.csdn.net/chuxue1342/article/details/8077197
* license: MIT & GPL
* last update: 16.10.2012
* version: 1.3.1
*/
var ac = function (c, o) {
this.cache = {}; // main chache {mask:[text]}
this.store = {}; // secondary cache {mask:strind}
this.pairs = {}; // cache of values {text:value}
this.init(c, o);
};
ac.prototype = {
// html elements
ac: null, // main input
ul: null, // autocomplete list
img: null, // image
container: null, // outer div
// timeouts
close: null, // ac hide
timeout: null, // ac search
// system definitons
chars: 0, // previous search string lenght
// user definitons
url: null, // url for ajax request
source: null, // <select/>, [], {} jQuery
minchar: 0, // minchars
delay: 50, // for search
fillin: false, // pre fill-in
type: 'xml', // ajax data type
width: 200, // width
top: false, // position top/bottom
writable: true, // writeable/selectable
values: false, // store values
partial: false,
// events, please use 'self' instead of 'this'
onSelect: function () {
},
onSetup: function () {
},
onKeyPress: function () {
},
onSuggest: function () {
},
onError: function () {
},
onSuccess: function () {
},
onDisplay: function () {
},
init: function (ac, options) {
var self = $.extend(this, options);
self.container = $('<div/>')
.css({ width: self.width })
.addClass('ac_conteiner')
.insertBefore(ac);
self.ac = $(ac)
.attr({ autocomplete: 'off' })
.blur(function () {
clearTimeout(self.close);
self.close = setTimeout(function () {
self.ul.hide();
}, 300);
}) // IE bug self.ul[.hide()] = undefined
.css({ width: (self.width - 22).toString() }) // 18 img + 2 margin + 2 border
.addClass('ac_input')
.appendTo(self.container);
self.img = $('<div/>')
.click(function () {
clearTimeout(self.close);
self.scroll();
self.ul.toggle();
self.ac.focus();
})
.addClass('ac_img')
.appendTo(self.container);
self.ul = $('<div/>')
.css({ width: self.width, marginTop: $(ac).outerHeight(true) })
.addClass('ac_results')
.appendTo(self.container)
.click(function () {
self.select();
self.ac.focus();
}).mousedown(function () {
setTimeout(function () {
clearTimeout(self.close);
self.ac.focus();
}, 50); // IE scroll bug
});
$(window).bind('resize load', function () {
var c = self.container;
self.ul.css({
width: self.width,
top: (self.top ?
c.offset().top - self.ul.height() - parseInt(c.css('border-top-width')) :
c.offset().top + c.height() + parseInt(c.css('border-bottom-width'))),
left: (c.offset().left + parseInt(c.css('border-left-width')))
});
});
if ($.browser.mozilla)
self.ac.bind('keyup', self, self.process);
else
self.ac.bind('keydown', self, self.process);
self.onSetup.apply(self, arguments);
if (self.fillin)
self.suggest('hide');
},
process: function (e) {
var self = e.data, len = self.ac.val().length;
self.onKeyPress.apply(self, arguments);
if (/^(27|38|40|13|9)$/.test(e.keyCode) && self.ul.is(':visible')) {
switch (e.keyCode) {
case 27: // escape
self.ul.hide();
break;
case 38: // up
self.prev();
break;
case 40: // down
self.next();
break;
case 13: // return
e.preventDefault();
case 9: // tab
self.select();
break;
}
} else if (!/^9$/.test(e.keyCode) && (len != self.chars || !len)) {
self.chars = len;
if (self.timeout)
clearTimeout(self.timeout);
self.timeout = setTimeout(function () {
self.suggest('show');
}, self.delay);
}
},
get: function () {
var self = this;
return self.ul.children('.ac_over');
},
prev: function () {
var self = this, current = self.get(), prev = current.prev();
if (current.length) {
current.removeClass('ac_over');
if (prev.length)
prev.addClass('ac_over');
}
if (!current.length || !prev.length) {
self.ul.children(':last').addClass('ac_over');
}
self.scroll();
},
next: function () {
var self = this, current = self.get(), next = current.next();
if (current.length) {
current.removeClass('ac_over');
if (next.length)
next.addClass('ac_over');
}
if (!current.length || !next.length)
self.ul.children(':first').addClass('ac_over');
self.scroll();
},
scroll: function () {
var self = this, current = self.get();
if (!current.length)
return; // quick return
var el = current.get(0), list = self.ul.get(0); // dont scroll after click on document :(
if (el.offsetTop + el.offsetHeight > list.scrollTop + list.clientHeight)
list.scrollTop = el.offsetTop + el.offsetHeight - list.clientHeight;
else if (el.offsetTop < list.scrollTop)
list.scrollTop = el.offsetTop;
},
select: function () {
var self = this, current = self.get();
if (current) {
self.ac.val(current.text());
self.ul.hide();
self.onSelect.apply(self, arguments);
}
},
suggest: function (show) {
var self = this, mask = $.trim(self.ac.val());
self.ul.hide();
if (mask.length >= self.minchar) {
self.onSuggest.apply(self, arguments);
if (self.check(mask) && !$.isFunction(self.url))
self.prepare(self.grab(mask), mask)[show]();
else if (self.url) // use ajax
$.ajax({ type: "GET", data: { mask: mask },
url: $.isFunction(self.url) ? self.url(self) : self.url,
success: function (xml) {
self.onSuccess.apply(self, arguments);
self.prepare(xml, mask)[show]();
},
error: function () {
self.onError.apply(self, arguments);
},
dataType: self.type
});
else if (self.source) // use source
self.prepare(self.source, mask)[show]();
} else {
self.ul.empty();
}
},
check: function (mask) {
var self = this;
if (self.cache[mask])
return true; // quick return
if (self.partial)
return false;
mask = mask.toLowerCase();
for (var it in self.cache)
if (it && !mask.indexOf(it.toLowerCase()))
return true;
return false;
},
grab: function (mask) {
var self = this, map = [], array = [];
if (self.cache[mask])
return self.cache[mask]; // quick return
for (var it in self.cache)
array.push(it);
array = array.reverse();
mask = mask.toLowerCase();
for (var item in array)
if (!mask.indexOf(array[item].toLowerCase())) {
for (var word in self.cache[array[item]])
if (!self.cache[array[item]][word].toLowerCase().indexOf(mask) > -1)
map.push(self.cache[array[item]][word]);
break;
}
return map;
},
prepare: function (xml, mask) {
var self = this, select = $(xml);
self.store[mask] = '';
self.cache[mask] = [];
if (!self.store[mask]) {
if (select.context) // use selectbox or ajax result
select.find("option").each(function (i, n) {
var t = $(n).text();
self.cache[mask].push(t);
self.store[mask] += self.mark(t, mask);
if (self.values && !self.pairs[t]) {
self.pairs[t] = $(n).attr("value");
}
});
else // use array or array-like object
$.each(xml, self.dataHandler(mask));
}
if (!self.writable && !self.cache[mask].length) {
setTimeout(function () {
var val = self.ac.val();
self.ac.val(val.substring(0, val.length - 1));
self.chars--;
}, 50);
return self.ul;
}
return self.display(self.store[mask]);
},
dataHandler: function (mask) {
var self = this;
return function (i, n) {
self.cache[mask].push(n);
self.store[mask] += self.mark(n, mask);
if (self.values && !self.pairs[n])
self.pairs[n] = i;
};
},
mark: function (text, mask) {
var i = text.toLowerCase().indexOf(mask.toLowerCase());
return i > -1 ?
'<div>' + text.replace(new RegExp(mask, 'ig'), function (mask) {
return '<span class="ac_match">' + mask + '</span>';
}) + '</div>' : '';
},
display: function (list) {
var self = this;
self.onDisplay.apply(self, arguments);
if (!list)
return self.ul.empty().end().end(); // fake
return self.ul.html(list).children('div').mouseover(function () {
$(this).siblings().removeClass('ac_over').end().addClass('ac_over');
}).eq(0).addClass('ac_over').end().end(); // ul
}
};
$.fn.autocomplete = function (options) {
this.each(function () {
if (this.tagName == 'SELECT' && !this.multiple) {
var select = $(this),
input = $("<input type='text'/>")
.addClass(select.attr('class'))
.attr('tabindex', select.attr('tabindex'))
.attr('id', 'ac_' + select.attr('id'));
select.after(input).hide(); // add text input and hide the select
$("label[for='" + select.attr('id') + "']")
.attr('for', 'ac_' + select.attr('id'));
new ac(input, $.extend({source: this, values: true, fillin: true, writable: false, onSelect: function () { select.val(this.pairs[this.ac.val()]); } }, options)); } else if (this.tagName == 'INPUT') { new ac(this, options); } }); return this; };})(jQuery);
CSS样式.ac_conteiner {
border: 1px solid #abadb3;
height: 20px;
}
.ac_input {
text-indent:2px;
font-size:1em;
font-family:sans-serif;
float: left;
padding:1px;
border: 0 !important;
height: 16px;
margin: 1px;
}
.ac_img {
width: 18px;
background: url('/Scripts/jqueryui/autocomplete/down.png');
height: 20px;
float:right;
cursor: pointer;
}
.ac_results {
border: 1px solid gray;
background-color: white;
padding: 0;
margin: 0;
list-style: none;
position: absolute;
z-index: 10000;
display: none;
overflow-x: hidden;
overflow-y: auto;
height: 100px;
margin-left: -1px !important; /*all*/
_margin-left:-3px !important; /*ie8*/
_margin-left:-1px; /*ie6*/
_margin-top: -1px !important; /*ieX*/
}
.ac_results div {
font-size:1em;
font-family:sans-serif;
padding-left: 2px;
white-space: nowrap;
}
.ac_over {
cursor: pointer;
background-color: #3399ff;
color: #fff;
}
.ac_match {
text-decoration: underline;
color: inherit;
margin: 0;
padding: 0;
}
html:first-child .ac_results {
/* opera <9.5 does not support css3 property overflow-y */
overflow: auto;
}用法参考:http://mabp.kiev.ua/content/2008/04/08/autocomplete/
本文介绍了一个基于jQuery的自动补全插件实现,该插件可通过AJAX请求获取建议列表,并支持最小字符数限制、延迟时间设置等功能。
210

被折叠的 条评论
为什么被折叠?



