这次给出自动填充插件的全部源代码和测试地址。
测试地址:http://jsbin.com/alaya4/2 能打开这个链接的就不用看下面的代码了。因为这个网站不支持中文,也不支持中文的@,所以更版本号是2

html和css
<!DOCTYPE html>
<html>
<head>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<meta charset=utf-8 />
<title>ac test</title>
<style type="text/css">
body{
font-size: 12px;
line-height: 20px;
font-family: Helvetica,Arial,sans-serif;
color:#555;
}
#wrapper{
display: inline;
position: relative;
border: 1px solid #DDDDDD;
float: left;
overflow: hidden;
width: 516px;
}
#inputarea,#shadow{
font-size: 12px;
line-height: 20px;
font-family: Helvetica,Arial,sans-serif;
width: 512px;
height: 100px;
border: 0px none;
margin: 0pt;
padding: 3px;
}
#shadow{
position: absolute;
top: 0pt;
left: 0pt;
z-index: -999;
overflow-y: scroll;
}
#selecter{
background-color: white;
border: 1px solid black;
color: #333333;
display: none;
font: 12px/1.75 Tahoma,Arial;
padding: 2px;
position: absolute;
z-index: 999;
}
#selecter ul{
margin:0;
padding:0;
}
#selecter ul li{
cursor: pointer;
list-style: none outside none;
margin: 0;
padding: 0 15px 0 5px;
white-space: nowrap;
}
#selecter ul li.on{
background-color: #EEEEEE;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="shadow"></div>
<textarea id="inputarea" ></textarea>
</div>
<div id="selecter"></div>
</body>
</html>
javascript文件
/**
* Author: kamal http://yukun.im/news/221
* Date: 2011-3-4
* Time: 14:25:37
* auto complete
*/
var strTMP = '{"r":24,"i":{"12345":"kamal", "12389":"luffy", "12387":"zoro", "12384":"nami", "12383":"usopp", "12382":"sanji", "12381":"chopper", "12376":"robin","12371":"franky", "12369":"brook", "12367":"vivi", "12366":"Shanks", "12348":"Beckman", "12347":"Yasopp", "12346":"Roo", "12447":"Rockstar", "12448":"Buggy", "12449":"Smoker", "12547":"Ace"}}';
function AC(oTxtbox, /*input area jQuery object*/
oSelecterLayer, /*div jQuery object*/
oShadow /*div jQuery object*/
){
this.nameLength = 16;
this.url = "data.js";
this.txtbox = oTxtbox;//textarea
this.selecterLayer = oSelecterLayer;//selecter panel div
this.shadow = oShadow;//shadow div
this.selecterPos = {top:0,left:0};//selecter panel coordinates
this.cursorX = 0; //cursor position in line
this.defaultList = null;//object id:name
this.curScrollTop = 0;//textarea scrolltop
this.curName = "";//string after @
this.selecterStr = "";//tmp var, selecter panel
this.selected = null;//tmp var, selected name
this.loading = false;//is ajax loading
this.enable = true;
this.init();
}
AC.prototype.init = function(){
var oThis = this;
this.txtbox[0].onkeyup = function(oEvent){
oEvent = oEvent || window.event;
oThis.handleKeyUp(oEvent);
};
this.txtbox[0].onkeydown = function(oEvent){
oEvent = oEvent || window.event;
if(oThis.selecterLayer.is(":visible") &&
( oEvent.keyCode == 38 || //up
oEvent.keyCode == 40 || //down
oEvent.keyCode == 13 || //enter
oEvent.keyCode == 9)){ //tab
oThis.stopDefault(oEvent); return;
}
};
};
AC.prototype.handleKeyUp = function(oEvent){
if(!this.enable){
return false;
}
var KEY = {
UP: 38,
DOWN: 40,
DEL: 46,
TAB: 9,
RETURN: 13,
ESC: 27,
COMMA: 188,
PAGEUP: 33,
PAGEDOWN: 34,
BACKSPACE: 8
};
var obj = this.selecterLayer;
var li = obj.find("li");
switch(oEvent.keyCode){
case KEY.UP:
if(obj.is(":visible")){
this.updatePos(this.selected.prev()[0] || li[li.length - 1]);
this.stopDefault(oEvent);
}
break;
case KEY.DOWN:
if(obj.is(":visible")){
this.updatePos(this.selected.next()[0] || li[0]);
this.stopDefault(oEvent);
}
break;
case KEY.RETURN:
case KEY.TAB:
if(obj.is(":visible")){
this.insert();
this.stopDefault(oEvent);
}
break;
default:
this.search();
break;
}
};
AC.prototype.search = function(){
if(this.txtbox.val().replace(/@/g, "@").indexOf('@') != -1){//if has @
//fetch name
this.fetchNameList();
//get cursor position
this.setCursorX();
//get user input name
var tmpName = this.txtbox.val().substr(0,this.cursorX).match(/@[^@\n\r]{0,30}$/g);
this.curName = tmpName?tmpName[0].slice(1):"";
if(this.curName !== ""){//alert('about to show suggest + currName='+this.curName);
this.showSelecterLayer();
}else{
this.hide();
}
}else{
this.hide();
}
};
AC.prototype.showSelecterLayer = function(){
this.fillShadow();
this.setSelecterPosition();
this.setSelecterStr();
if(this.selecterStr !== ""){
this.selecterLayer.css({top:this.selecterPos.top+"px",left:this.selecterPos.left+"px"})
.html(this.selecterStr)
.show();
this.selected = this.selecterLayer.find("li:first").addClass("on");
this.bindHover();
}else{
this.hide();
}
};
AC.prototype.updatePos = function(elem){
this.selected = $(elem);
this.selecterLayer.find("li").removeClass("on");
this.selected.addClass("on");
};
AC.prototype.insert = function(){
var str = this.selected.html().replace(/\<\/?b\>|\(.*\)/ig,"");
var txttmp = this.txtbox.val().substr(0,this.cursorX);
var txt1 = txttmp.substr(0,txttmp.lastIndexOf('@')+1);
var txt2 = this.txtbox.val().substr(this.cursorX);// alert('to insert -- '+txt1+'+' + str + " +" +txt2);
this.txtbox.val(txt1 + str + " " +txt2 ).focus();
this.setCursorX(txt1.length + str.length + 1);
this.hide();
};
AC.prototype.setSelecterPosition = function(){
//var absposition = ugAbsPos(this.shadow.find("span")[0]);
var pos = this.shadow.find("b").position();
this.selecterPos.top = pos.top + 25;
this.selecterPos.left = pos.left;
this.curScrollTop = this.txtbox[0].scrollTop;
this.selecterPos.top = this.selecterPos.top - this.curScrollTop;
};
AC.prototype.fillShadow = function(){//alert('-'+this.txtbox.val()+'-');
var tmpTxt = this.txtbox.val().substr(0,this.cursorX).replace(/@/g, "@").replace(/ /g," ").replace(/\r\n|\n/g, "<br />");
var txt1 = tmpTxt.substr(0,tmpTxt.lastIndexOf('@')+1);
this.shadow.html("<span>"+txt1 + "</span><b>" + this.curName + "</b>");
};
AC.prototype.setSelecterStr = function(){
var tmpStr = "";
var data = this.defaultList;
var regStr = this.escapeReg(this.curName);
var reg = eval("/^"+ regStr +"/i");
if(this.defaultList){
var suggest_count = 0;
for(var p in data){// alert(p + "\n"+data[p]);
if(suggest_count >= 10){break;}
var tmpname = data[p];
var matchStr = tmpname.match(reg);
if(matchStr != null){
suggest_count++;
tmpStr += '<li>'+tmpname.replace(reg,'<b>'+matchStr+'</b>')+'('+p+')</li>';
}
}//end of for
if(tmpStr != ""){
this.selecterStr = "<ul>"+tmpStr+"</ul>";
}else{
this.selecterStr = "";
}
}
};
AC.prototype.hide = function(){
this.selecterLayer.hide();
};
AC.prototype.bindHover = function(){
var oThis = this;
this.selecterLayer.find("li").mouseover(function(){
$(this).parent().find("li").removeClass("on");
oThis.selected = $(this).addClass("on");
});
this.selecterLayer[0].onclick = function(){
oThis.insert();
};
};
AC.prototype.fetchNameList = function(){
var oThis = this;
if(oThis.defaultList == null && !this.loading){
oThis.loading = true;
oThis.defaultList = eval('('+strTMP+')').i;
// $.ajax({
// url:this.url,
// type:'get',
// dataType:'json',
// success:function(data){
// if(data.r && data.r>0){
// oThis.defaultList = data.i;
// }
// },
// finish:function(){
// oThis.loading = false;
// },
// error:function(data){
// alert(data);
// }
// });
oThis.selected = null;
}
};
AC.prototype.setCursorX = function(pos){
var obj = this.txtbox[0];
if(document.selection){
var rng = document.selection.createRange();
if(pos === undefined){
obj.focus();
if(rng == null){
this.cursorX = 0;
}
var re = obj.createTextRange(),
rc = re.duplicate();
re.moveToBookmark(rng.getBookmark());
rc.setEndPoint('EndToStart',re);
this.cursorX = rc.text.length;
}else if(typeof pos === "number"){
obj.focus();
var index = this.cursorX;
var range = obj.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}else{
if(pos === undefined){
this.cursorX = obj.selectionStart;
}else if(typeof pos === "number"){
obj.scrollTop = this.curScrollTop;
obj.focus();
obj.selectionEnd = pos;
obj.selectionStart = pos;
}
}
};
AC.prototype.escapeReg = function(a){
for(var b = [], c = 0; c < a.length; c ++ )
{
var e = a.charAt(c);
switch(e)
{
case "." :
b.push("\\x2E");
break;
case "$" :
b.push("\\x24");
break;
case "^" :
b.push("\\x5E");
break;
case "{" :
b.push("\\x7B");
break;
case "[" :
b.push("\\x5B");
break;
case "(" :
b.push("\\x28");
break;
case "|" :
b.push("\\x28");
break;
case ")" :
b.push("\\x29");
break;
case "*" :
b.push("\\x2A");
break;
case "+" :
b.push("\\x2B");
break;
case "?" :
b.push("\\x3F");
break;
case "\\" :
b.push("\\x5C");
break;
case "/" :
b.push("\\x2F");
break;
default :
b.push(e);
}
}
return b.join("");
};
AC.prototype.stopDefault = function(e){
if ( e && e.preventDefault )
e.preventDefault();
else
window.event.returnValue = false;
return false;
};
//-------------------
new AC($('#inputarea'), /*input area jQuery object*/
$('#selecter'), /*div jQuery object*/
$('#shadow') /*div jQuery object*/);