在寫頁面時,我們有時會有這樣的需求,要下拉框可選可輸入,該腳本就是可輸可選控件.該腳本是根據網上某大俠源腳本改編而成,現記錄在此,以備后用.
新增功能: 支持模糊定位、支持上下箭選擇、支持注釋層功能、支持按回車鍵從下拉框中選擇選項
源碼引自:http://blog.csdn.net/cxzhq2002
資源來自:http://jiangzhengjun.iteye.com/blog/455171
效果圖:
//下拉框選項所對應的層的名字 var SELECT_DIV="SELECT_DIV_"; //注釋層的名字 var NODE_DIV="NODE_DIV_"; var textObject; //焦點是否在選擇層上:初始時為false,表示默認不在選擇層上 //主要防止鼠標點擊選擇項時,文本框會失去焦點,這樣選擇層就會跟着隱藏,此時還未 //讓點擊的選擇項選中並賦值到文本框中去。此時可以設置鼠標在選擇層上時cursorInSelectDivObj=ture //這時點擊時不會立即隱藏選擇層,等選中后再設置cursorInSelectDivObj=false,此時就可以隱藏選擇層了 var cursorInSelectDivObj=false; //是否是ie瀏覽器 var ie=(document.getElementById && document.all); //全局的注釋數組 var noteArr = new Array(); //以防名字已存在,循環取名,先判斷是否存在"Textselectshow_Div"的對象, //如果存在,則重新取名為"Textselectshow_Div1",如果"Textselectshow_Div1" //還是存在,則取名為"Textselectshow_Div2",依次類推:"Textselectshow_Div..." for(var i=0;document.getElementById(SELECT_DIV)!=null;i++){ var tmpNm = SELECT_DIV + i; //如果存在同名的,則以重新取名為 Textselectshow_Div + i ,如果Textselectshow_Div + i //存在,則循環取名為 Textselectshow_Div + i + 1,直到不重名為止。如果存在,則賦值為本身再循環 SELECT_DIV=(document.getElementById(tmpNm)==null)?tmpNm:SELECT_DIV; } //以同樣的命名方式為注釋層取名 for(var i=0;document.getElementById(NODE_DIV)!=null;i++){ var tmpNm = NODE_DIV + i; NODE_DIV=(document.getElementById(tmpNm)==null)?tmpNm:NODE_DIV; } //為隱藏下拉框創建一個對應的層,並且剛初始化時為隱藏的 document.write ('<div id="' + SELECT_DIV + '" style="position: absolute;' + 'cursor: default;border: 1px solid #B2B2B2;background-color: #fff;display: none;"></div>') //同樣方式創建一個注釋層 document.write ('<div id="' + NODE_DIV + '" style="position: absolute;' + 'cursor: default;border: 1px solid #B2B2B2;background-color:#ffffd9;display: none;' + 'overflow-x:auto;word-wrap:break-word"></div>') // 獲取某對象的坐標 function getObjPosition(Obj){ try{ var sumTop=0; var sumLeft=0; while(Obj!=window.document.body){ sumTop+=Obj.offsetTop; sumLeft+=Obj.offsetLeft; Obj=Obj.offsetParent; } return {left:sumLeft,top:sumTop}; }catch(e){alert(e);} } //處理Div中的選項/* 某個選項,文本框的ID */ function optionDivOnmouseover(optionDivObj,textId){ //文本框 var textObj=document.getElementById(textId); //optionDivObj.parentNode為某select option選項所對應層的父對象,即SELECT_DIV層 //得到select下拉框所有option選項所對應的層 var objChilddiv=optionDivObj.parentNode.getElementsByTagName("div"); //清空所有選項層的樣式,即去掉原來背景為藍色的選項層的樣式 for(var i=0; i < objChilddiv.length; i++){ objChilddiv[i].style.cssText=''; } //使本身選項層的背景為藍色,字為白色,模擬選中樣式 optionDivObj.style.cssText='background-color: #330066;color: #ffffff;' var noteDivObj =document.getElementById(NODE_DIV); var selectDivObj =document.getElementById(SELECT_DIV); ///////設置注釋層中的選項及位置 setNoteDivObj(textObj,optionDivObj,selectDivObj,noteDivObj); //點擊某個選項層時 optionDivObj.onclick=function(){ //點擊選項后選擇層后要隱藏,即要設置成失去焦點狀態 cursorInSelectDivObj=false; //把選中的某選項層的內容賦值為文本框 if(ie){ textObj.value=optionDivObj.outerText; } else { textObj.value=optionDivObj.textContent; } //var noteDivObj =document.getElementById(NODE_DIV); //點擊某個選項層時,對應的注釋層也要隱藏 noteDivObj.style.display='none'; //點擊過后使文本框獲取焦點 textObj.focus(); ////////調用文本框失去焦點觸發的方法 textObjectBlur(selectDivObj,noteDivObj); } } /** * textObj:文本框 * seleObj:下拉框 * noteArr:noteArr 注釋數組,沒有可以不傳或為null或空數組 */ function showSelect(textObj,seleObj,arrNote){ textObject = textObj; //保存全局注釋,供其他方法使用 noteArr = arrNote; var selectDivObj =document.getElementById(SELECT_DIV); var noteDivObj =document.getElementById(NODE_DIV); var seleObj =document.getElementById(seleObj); ///////鼠標移出下拉框層時 selectDivObj.onmouseout=function(){ //當鼠標移出選擇層時,設置選擇層為失去焦點狀態 cursorInSelectDivObj=false; //當鼠標移出選擇層時,讓文本框獲取焦點 textObj.focus(); } ///////文本框失去焦點時 textObj.onblur=function(){ textObjectBlur(selectDivObj,noteDivObj); } ///////鼠標經過下拉框層時 selectDivObj.onmouseover=function(){ //當鼠標移進選擇層時,設置選擇層為獲得焦點狀態 cursorInSelectDivObj=true; } ///////文本框點擊時 textObj.onclick=function(){ //設置下拉框對應層中的選項及位置 setSelectDivObj(textObj,selectDivObj,seleObj); //設置注釋層中的選項及位置 setNoteDivObj(textObj,null,selectDivObj,noteDivObj); //自動匹配與模糊定位 autoMatch(textObj,selectDivObj); } ///////文本框上輸入時 textObj.onkeyup=function(){ //如果按的是Tab鍵時直接退出 if(event.keyCode==9){ return false; } if(event.keyCode==13){ enter(textObj,selectDivObj,noteDivObj); return false; } //設置下拉框對應層中的選項及位置 setSelectDivObj(textObj,selectDivObj,seleObj); //如果按了上下鍵時 if(event.keyCode == 38 || event.keyCode == 40 ){ var selectedOptionDiv = downOrUp(textObj,selectDivObj,noteDivObj,seleObj); //設置注釋層中的選項及位置 setNoteDivObj(textObj,selectedOptionDiv,selectDivObj,noteDivObj); }else{ //設置注釋層中的選項及位置 setNoteDivObj(textObj,null,selectDivObj,noteDivObj); } //自動匹配與模糊定位 autoMatch(textObj,selectDivObj); } } // 隱藏遮擋ID為objID的對象(層)的所有select function hiddenOverSelects(objID){ var sels = document.getElementsByTagName('select'); for (var i = 0; i < sels.length; i++){ if (obj1OverObj2(document.getElementById(objID), sels[i])){ sels[i].style.visibility = 'hidden'; }else{ sels[i].style.visibility = 'visible'; } } } //判斷obj1是否遮擋了obj2 function obj1OverObj2(obj1, obj2){ var pos1 = getObjPosition(obj1) var pos2 = getObjPosition(obj2) var result = true; var obj1Left = pos1.left - window.document.body.scrollLeft; var obj1Top = pos1.top - window.document.body.scrollTop; var obj1Right = obj1Left + obj1.offsetWidth; var obj1Bottom = obj1Top + obj1.offsetHeight; var obj2Left = pos2.left - window.document.body.scrollLeft; var obj2Top = pos2.top - window.document.body.scrollTop; var obj2Right = obj2Left + obj2.offsetWidth; var obj2Bottom = obj2Top + obj2.offsetHeight; if (obj1Right <= obj2Left || obj1Bottom <= obj2Top || obj1Left >= obj2Right || obj1Top >= obj2Bottom) result = false; return result; } //文本框失去焦點時調用的方法 function textObjectBlur(selectDivObj,noteDivObj){ //如果點擊了某個選項后,已設置選擇層為失去焦點狀態,此時選擇層可以隱藏了 if(!cursorInSelectDivObj){ selectDivObj.style.display='none'; } if(ie){ //恢復所有已被隱藏的下拉框 hiddenOverSelects(selectDivObj.id); if(noteDivObj.style.display=='inline'){ noteDivObj.style.display=selectDivObj.style.display; } if(selectDivObj.style.display=='none'){ noteDivObj.style.display='none'; } } } //設置下拉框對應層中的選項及層位置 function setSelectDivObj(textObj,selectDivObj,seleObj){ //如果已顯示,則直接退出 if(selectDivObj.style.display=='inline'){ return false; } //如果文本框的id為空時,則要命名 for(var i=0;textObj.id=='';i++){ var tmpNm = "textSelect" + i; textObj.id = (document.getElementById(tmpNm)==null)?tmpNm:''; } selectDivObj.style.left = getObjPosition(textObj).left; selectDivObj.style.top = getObjPosition(textObj).top + textObj.offsetHeight; selectDivObj.style.width = textObj.offsetWidth; selectDivObj.style.height = ''; selectDivObj.style.overflowY = ''; selectDivObj.innerHTML='' //讀取select的項目放到Div里。 for(var x = 0; x<seleObj.options.length; x++){ selectDivObj.innerHTML+="<div onmouseover=\"optionDivOnmouseover(this,'" + textObj.id + "')\" style='width:100%;white-space: nowrap;cursor: default;'>" +seleObj.options[x].text+"</div>"; } //調整Div高度,過度顯示滾動條 if(x > 8){ selectDivObj.style.height=13 * 8; selectDivObj.style.overflowY='auto'; }else{ selectDivObj.style.height=15 * x; selectDivObj.style.overflowY='auto'; } selectDivObj.style.display='inline'; if(ie){ hiddenOverSelects(selectDivObj.id); } } //設置下拉框對應層中的選項及層位置 function setNoteDivObj(textObj,optionDivObj,selectDivObj,noteDivObj){ //如果需要顯示對應鍵的注釋時 if(noteArr != null && noteArr != undefined){ //獲取下拉框所對應的層的寬度與左邊距 var regStr = new RegExp("(([0-9]+)px)"); selectDivObj.style.width.match(regStr); var width=RegExp.$2; regStr = new RegExp("(([0-9]+)px)"); selectDivObj.style.left.match(regStr); var left= RegExp.$2; //設置注釋層的位置與大小 noteDivObj.style.left=parseInt(width) +parseInt(left); noteDivObj.style.top=selectDivObj.style.top; noteDivObj.style.width=width*1; noteDivObj.style.height=selectDivObj.style.height; var i = 0; //如果找到對應的注釋,則顯示注釋層 for(i = 0;i < noteArr.length;i++){ if(optionDivObj==null && textObj.value == noteArr[i][0]){ noteDivObj.innerText=noteArr[i][1]; noteDivObj.style.display="inline"; break; }else if(optionDivObj !=undefined && optionDivObj !=null && optionDivObj.outerText == noteArr[i][0]){ noteDivObj.innerText=noteArr[i][1]; noteDivObj.style.display="inline"; break; } } if(i==noteArr.length){ noteDivObj.innerText=''; noteDivObj.style.display="none"; } } } //自動匹配選項中符合文本框中輸入的值的記錄 function autoMatch(textObj,selectDivObj){ if(textObj.value==''){ return null; } if(event.keyCode == 38 || event.keyCode == 40 ){ return null; } return autoMatch_(textObj,selectDivObj); } //String.fromCharCode function autoMatch_(textObj,selectDivObj){ var objChilddiv=selectDivObj.getElementsByTagName("div"); var arr = new Array(); //清除所有層的樣式 for(var x=0;x<objChilddiv.length;x++){ objChilddiv[x].style.cssText=''; } var selectOptionDivObj = null; var textValueReg = replaceReg(textObj.value); for(var x=0;x<objChilddiv.length;x++){ var strChilddiv=(ie)?objChilddiv[x].outerText:textObj.textContent; var regRegExp = new RegExp('^'+textValueReg); //alert('^'+textValueReg + " " + strChilddiv + " " + textObj.value); //先模糊匹配 if(regRegExp.test(strChilddiv)){ //讓模糊匹配到的選項上移 selectDivObj.scrollTop=objChilddiv[x].offsetHeight*x; //再精確匹配,且讓精確匹配的成選中狀態 if(strChilddiv==textObj.value){ arr[0]=objChilddiv[x]; arr[1]=x; objChilddiv[x].style.cssText='background-color: #330066;color: #ffffff;'; break; }else{ objChilddiv[x].style.cssText=''; } break; }else{ objChilddiv[x].style.cssText=''; } textObj.focus(); } return arr; } //上下翻 function downOrUp(textObj,selectDivObj,noteDivObj,seleObj){ //得到select下拉框所有option選項所對應的層 var objChilddiv=selectDivObj.getElementsByTagName("div"); if(objChilddiv.length == 0){ return null; } var selectedOptionDiv; var hig = 0; if(event.keyCode==38){ selectedOptionDiv = objChilddiv[objChilddiv.length -1]; hig = objChilddiv.length -1; }else if(event.keyCode==40){ selectedOptionDiv = objChilddiv[0]; hig = 0; }else{ selectedOptionDiv = objChilddiv[0]; } var i=0; //清空所有選項層的樣式,即去掉原來背景為藍色的選項層的樣式 for(i=0; i < objChilddiv.length; i++){ if(objChilddiv[i].style.backgroundColor=='#330066'){ if(event.keyCode==38){ if(i != 0){ selectedOptionDiv = objChilddiv[i - 1]; hig = i - 1; }else{ selectedOptionDiv = objChilddiv[objChilddiv.length - 1]; hig = objChilddiv.length -1; } }else if(event.keyCode==40){ if(i != (objChilddiv.length -1)){ selectedOptionDiv = objChilddiv[i + 1]; hig = i + 1; }else{ selectedOptionDiv = objChilddiv[0]; hig = 0; } } objChilddiv[i].style.cssText=''; break; } } //解決用上下鍵彈出下拉列表時,讓列表中與文本框相同值的選項選中 if(i==objChilddiv.length){ //自動匹配與模糊定位 var selectOption = autoMatch_(textObj,selectDivObj); if(selectOption.length != 0){ //設置注釋層中的選項及位置 setNoteDivObj(textObj,selectOption,selectDivObj,noteDivObj); selectedOptionDiv = selectOption[0]; hig = selectOption[1]; } } selectDivObj.scrollTop=selectedOptionDiv.offsetHeight*hig; //使本身選項層的背景為藍色,字為白色,模擬選中樣式 selectedOptionDiv.style.cssText='background-color: #330066;color: #ffffff;' textObj.focus(); return selectedOptionDiv; } //回車 function enter(textObj,selectDivObj,noteDivObj){ if(selectDivObj.style.display=='none'){ return false; } //得到select下拉框所有option選項所對應的層 var objChilddiv=selectDivObj.getElementsByTagName("div"); if(objChilddiv.length == 0){ return false; } var selectedOptionDiv; //清空所有選項層的樣式,即去掉原來背景為藍色的選項層的樣式 for(var i=0; i < objChilddiv.length; i++){ if(objChilddiv[i].style.backgroundColor=='#330066'){ textObj.value=(ie)?objChilddiv[i].outerText:objChilddiv[i].textContent; //回車時相當於點擊了某個選項,此時設置選擇層為失去焦點狀態 //再調用文本框失去焦點方法textObjectBlur讓選擇層隱藏 cursorInSelectDivObj=false; textObjectBlur(selectDivObj,noteDivObj); break; } } } var regChars = new Array(); regChars[0]=new Array(); regChars[0][0]="$"; regChars[0][1]="\\$"; regChars[1]=new Array(); regChars[1][0]="("; regChars[1][1]="\\("; regChars[2]=new Array(); regChars[2][0]=")"; regChars[2][1]="\\)"; regChars[3]=new Array(); regChars[3][0]="*"; regChars[3][1]="\\*"; regChars[4]=new Array(); regChars[4][0]="+"; regChars[4][1]="\\+"; regChars[5]=new Array(); regChars[5][0]="."; regChars[5][1]="\\."; regChars[6]=new Array(); regChars[6][0]="["; regChars[6][1]="\\["; regChars[7]=new Array(); regChars[7][0]="?"; regChars[7][1]="\\?"; regChars[8]=new Array(); regChars[8][0]="]"; regChars[8][1]="\\]"; regChars[9]=new Array(); regChars[9][0]="^"; regChars[9][1]="\\^"; regChars[10]=new Array(); regChars[10][0]="|"; regChars[10][1]="\\|"; regChars[11]=new Array(); regChars[11][0]="{"; regChars[11][1]="\\{"; regChars[12]=new Array(); regChars[12][0]="}"; regChars[12][1]="\\}"; regChars[13]=new Array(); regChars[13][0]="\\"; regChars[13][1]="\\\\"; //代換正則表達式中特殊字符 function replaceReg(str){ //$()*+.[?]^|}{\ var regStr =/[$()*+.\[?\]^|}{\\]/g; if(!str.match(regStr)){ return str; } var regArr =/./g; var valueArr = str.match(regArr); var tempStr = ""; for(var i = 0 ; i < valueArr.length; i++){ regStr =/[$()*+.\[?\]^|}{\\]/g; if(valueArr[i].match(regStr)){ valueArr[i] = findByKey(valueArr[i])[1]; } tempStr = tempStr + valueArr[i]; } return tempStr; } //查詢正則特殊字符要替換字符串 function findByKey(key){ var i = 0; for(var i = 0; i < regChars.length; i++){ if(regChars[i][0]==key){ return regChars[i]; } } if(i == regChars.length ){ return null; } } //在最后一個輸入元素上按回車鍵時自動提交 function keydownOnSelectInput(){ if(event.srcElement.type == undefined){ return; } var type = event.srcElement.type.toLowerCase(); if(event.keyCode!=13 || type=='button' || type=='submit' || type=='reset' || type=='textarea' || type==''){ return; } var noteDivObj =document.getElementById(NODE_DIV); var selectDivObj =document.getElementById(SELECT_DIV); if(event.srcElement.nextSibling != null && event.srcElement.nextSibling.type=='select-one' && selectDivObj.style.display=='inline'){ var objChilddiv=selectDivObj.getElementsByTagName("div"); var i=0; for(i=0; i < objChilddiv.length; i++){ if(objChilddiv[i].style.backgroundColor=='#330066'){ break; } } //在可選可輸入文本框上按回車時,如果下拉列表中沒有選中項,則直接跳到下一輸入元素 if(i == objChilddiv.length){ cursorInSelectDivObj=false; textObjectBlur(selectDivObj,noteDivObj); event.keyCode=9; }else{ event.returnValue=false; } return; } var srcForm = event.srcElement.form; if(srcForm == undefined || srcForm == null){ return ; } var srcForm = event.srcElement.form; var srcElementNext = null; var allElems = srcForm.elements; for(var i = 0; i < allElems.length; i++){ if(event.srcElement == allElems[i]){ if(!isLastElem(allElems,i+1)){ event.keyCode=9; break; }else { if(event.srcElement.type=='select-one'){ var subButton = findSubmitButton(allElems,i); if(subButton !=null){ subButton.click(); } } } } } } //查找提交按鈕 function findSubmitButton(allElems,index){ for(var i = index; i < allElems.length; i++){ if(allElems[i].type=='submit'){ return allElems[i]; } } return null; } //判斷是否是最后一個元素 function isLastElem(allElems,index){ if(index >=allElems.length || allElems[index].type=="submit" ){ return true; } for(var i = index; i < allElems.length; i++){ var tempObj = allElems[i]; while(tempObj != window.document.body){ //如果該元素未隱藏,則判斷父元素是否隱藏 if(tempObj.style.display != 'none'){ tempObj=tempObj.parentElement; }else{ //如果輸入元素隱藏,則遞歸查找其他輸入元素是否隱藏 return isLastElem(allElems,i+1); } } //如果某輸入元素本身未隱藏,且其父也未隱藏,則不是最后一輸入元素 if(tempObj == window.document.body){ return false; } } } //自動綁定按鍵事件 window.document.onkeydown = keydownOnSelectInput; window.onresize=function(){ if(textObject){ textObject.blur(); } }