这次给出自动填充插件的全部源代码和测试地址。
测试地址: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*/);