HTML可输可选下拉框实现的JavaScript脚本

在写页面时,我们有时会有这样的需求,要下拉框可选可输入,该脚本就是可输可选控件.该脚本是根据网上某大侠源脚本改编而成,现记录在此,以备后用.

 

源码引自:http://blog.csdn.net/cxzhq2002 

 

新增功能: 支持模糊定位、支持上下箭选择、支持注释层功能、支持按回车键从下拉框中选择选项   

 

 效果图如下所示:

 效果图  

 

//下拉框选项所对应的层的名字
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.οnclick=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.οnmοuseοut=function(){		
		//当鼠标移出选择层时,设置选择层为失去焦点状态	
		cursorInSelectDivObj=false;
		
		//当鼠标移出选择层时,让文本框获取焦点
		textObj.focus();
	}
	
	///文本框失去焦点时
	textObj.οnblur=function(){
		textObjectBlur(selectDivObj,noteDivObj);		
	}
	
	///鼠标经过下拉框层时
	selectDivObj.οnmοuseοver=function(){
		//当鼠标移进选择层时,设置选择层为获得焦点状态	
		cursorInSelectDivObj=true;
	}
		
	///文本框点击时
	textObj.οnclick=function(){
 		//设置下拉框对应层中的选项及位置
		setSelectDivObj(textObj,selectDivObj,seleObj);

		//设置注释层中的选项及位置
		setNoteDivObj(textObj,null,selectDivObj,noteDivObj);
		
		//自动匹配与模糊定位
		autoMatch(textObj,selectDivObj);	
 	}
 	
 	///文本框上输入时
 	textObj.οnkeyup=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 οnmοuseοver=\"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.οnresize=function(){
		if(textObject){
			textObject.blur();
		}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值