HTML可輸可選下拉框實現的JavaScript腳本


在寫頁面時,我們有時會有這樣的需求,要下拉框可選可輸入,該腳本就是可輸可選控件.該腳本是根據網上某大俠源腳本改編而成,現記錄在此,以備后用.

新增功能: 支持模糊定位、支持上下箭選擇、支持注釋層功能、支持按回車鍵從下拉框中選擇選項 

源碼引自: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();  
        }  
}  

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM