文本域 自定义下拉框 支持模糊检索 关键字高亮 上下选择

转载自:文本域 自定义下拉框 支持模糊检索 关键字高亮 上下选择

一、需求

需要创建一个常见问题库,填写存在问题时可以下拉选择,可以模糊搜索,也可以手写。如果选择了问题库中的内容,自动填充内容到存在问题中,并且自动选择严重程度,最终保存的值还是界面显示的内容。

二、可行性研究

1、h5的datalist 可以支持下拉选择,模糊搜索,手写 。经过试验 list属性只能用于input输入框  不可适用于textarea。 无法直接使用datalist方式,pass。

2、使用input的datalist和textarea结合的方式,界面显示textarea。点击变成input使用datalist方式进行检索,填写完成后转成textarea。 经过试验,功能可以达到,但是input不换行,用户体验太差,pass。

3、使用semantic ui的输入框  也不支持textarea,pass。

4、手写下拉框,可行。

三、实现

1、实现思路

a、点击文本框,弹出下拉框。下拉框以td绝对定位,根据页面高度计算位置,下拉框是在td上面还是下面

b、点击空白处关闭下拉框

c、文本域输入内容,检索下拉框匹配内容,高亮显示关键字,隐藏没有匹配项内容

d、监听键盘上下键,动态选择下拉框内容,并自动填充值

 

2、在页面创建临时div 默认隐藏 用于缓存数据

JavaScript

	<div id="tempQuestionDiv" style="display:none">
		<ul>
		<#list problemList as list>
			<li><span severityLevel="${list.severityLevel}">${list.questionContent}</span><dd>${list.severityLevelName}</dd></li>
		</#list>
		</ul>
	</div>

 

3、页面结构

image.png

image.png

td中一个textarea

4、界面样式

CSS

.deductCheckInfo{
   position: relative;
}

#questionDiv{
    border: 1px solid #96C8DA;
    width: 321px;
    height: 300px;
    z-index: 9999;
    position: absolute;
    text-align:left;
    background: white;
    border-radius:5px;
    padding: 5px 6px;
    overflow-y: scroll;
}
#questionDiv ul li{
padding:3px 6px;
cursor: pointer;
	
}
#questionDiv ul li span{
	margin-bottom: 5px;
    color: #333;
    font-size: 13px;
    display: block;
    line-height: 18px;
}

#questionDiv ul li dd{
    color: #333;
    font-size: 13px;
    display: block;
    opacity: 0.7 ;
}

#questionDiv ul .active{
	    background: rgba(0, 0, 0, 0.07);
	    /* font-weight: 600; */
}

#questionDiv ul li:hover{
	 background: rgba(0, 0, 0, 0.14);
}

 

 

5、事件绑定和提取方法

 

a、文本域点击事件

JavaScript

//输入框点击事件
        $("body").on("click",".deductCheckInfo textarea",function(event){
        	 var that=this;
        	 //先删除已有的下拉框
        	 $("#questionDiv").remove();
        	 //重新获取下拉框内容
        	 var tempQuestionDiv=$("#tempQuestionDiv").html();
        	 //判断当前td下是否存在下拉框
        	 var $QuestionDiv=$(this).parent().find("#questionDiv");
        	 //当前td下不存在下拉框
        	 if($QuestionDiv && $QuestionDiv.length==0){
        		 //添加下拉框
        		 $(this).after("<div id=\"questionDiv\">"+tempQuestionDiv+"</div>");
        		 //获取下拉框的高度  获取包括padding的高度加上边框线高度
        		 var questionDivHeight=$("#questionDiv").innerHeight()+2;
        		 //获取td的高度
        		 var deductCheckInfoTdHeight=$(this).parent().innerHeight();
        		 //获取td的Y坐标
        		 var tdY=$(this).parent().offset().top;
        		 //获取页面高度(下边距60+form表单高度+form表单距离顶部的高度)
        		 var formHeight=60+$("div.form").innerHeight()+$("div.form").offset().top;
        		 //高度差  td左下角位置离页面底部的距离(页面高度-td的坐标-td的高度)
        		 var tempHeight=formHeight-tdY-deductCheckInfoTdHeight;
        		 //TD距离页面底部的距离小于下拉框高度时  且 (td的Y减去tab项的高度)大于下拉框高度时
        		 if(tempHeight<questionDivHeight && (tdY-$("#checkImplementTab").height())>questionDivHeight){
        			 //将下拉框向上移动 避免遮挡
        			 var top=-(questionDivHeight);
        			 //移动
        			 $("#questionDiv").css("top",top)
        		 }
        		 //点击事件
                 $("#questionDiv").find("ul li").click(function(){
                	 //获取li的jq对象
                	 var $li=$(this);
                	 //获取textarea的jq对象
                	 var $textarea=$(that);
                	 //下拉框回写数据
                	 selectProblemData($li,$textarea);
                 });
        	 }
        	 //获取当前文本域内容
        	 var textareaVal=$(this).val();
        	 //下拉框内容检索和显示
        	 selectProblemShow(textareaVal);
        	 //取消冒泡
        	 event.stopPropagation();
         });

b、文本框输入内容

JavaScript

//监听文本框输入内容
         $(".deductCheckInfo textarea").on("input propertychange",function(e){
        	 //获取当前输入内容
        	 var curText=$(this).val();
        	//下拉框内容检索和显示
        	 selectProblemShow(curText);
         });

c、监听键盘按键

JavaScript

//监听文本框键盘按键
         $(".deductCheckInfo textarea").on("keydown",function(e){
        	 var keyCode=e.keyCode;
			//判断下拉框显示的时候 并且只有 上下键 才触发
			if(!$("#questionDiv").is(":hidden") && (keyCode==38 || keyCode==40)){
				//需要改为显示的全部li
				var thisliall=$("#questionDiv ul li");
				//显示的全部li
				var thisli=new Array();
				thisliall.each(function(){
					if(!$(this).is(":hidden")){
						thisli.push($(this));
					}
				});
	        	//当前选中的li标签
	        	var activeLi=$("#questionDiv ul li[class='active']");
	        	//文本域jq对象
	        	var $textarea=$(this);
	        	//下一个需要选中的li
	        	var $nextLi;
	        	//下一行是否是第一行
	        	var firstFlag=false;
	        	//上一行是否是最后一行
	        	var lastFlag=false;
	        	//如果没有选中的数据
	        	if(activeLi && activeLi.length==0){
	        		//向上  添加最后一行作为下一个需要选中的li
	        		if(keyCode==38){
	        			$nextLi=$(thisli[thisli.length-1]);
	        			lastFlag=true;
	        			//向上滚动
	        			srollUpFun($nextLi,lastFlag);
	        		//向下  添加第一行作为下一个需要选中的li 
	        		}else if(keyCode==40){
	        			$nextLi=$(thisli[0]);
	        			firstFlag=true;
	        			//向下滚动
	        			srollDownFun($nextLi,firstFlag);
	        		}
	        	//如果有选中的数据
	        	}else{
	        		//向上 递归选中上一行
	        		if(keyCode==38){
	        			$nextLi=getPrevShowLi(activeLi);
	        			//如果没有上一行,则设置第一行为下一行
	        			if($nextLi && $nextLi.length==0){
	        				$nextLi=$(thisli[thisli.length-1]);
	        				lastFlag=true;
	        			}
	        			//向上滚动
	        			srollUpFun($nextLi,lastFlag);
	        		//向下 递归选中下一行
	        		}else if(keyCode==40){
	        			$nextLi=getNextShowLi(activeLi);
	        			//如果没有下一行,则设置第一行为下一行
	        			if($nextLi && $nextLi.length==0){
	        				$nextLi=$(thisli[0]);
	        				firstFlag=true;
	        			}
	        			//向下滚动
	        			srollDownFun($nextLi,firstFlag);
	        		}
	        	}
	        	//清除当前选中
    			activeLi.removeClass("active");
	        	//下一个li添加选中
    			$nextLi.addClass("active");
    			//下拉框回写数据
    			selectProblemData($nextLi,$textarea);
			}
         });

d、空白处点击事件

JavaScript

//点击空白处隐藏删除下拉框
$(document).click(function(e){
    	    $("#questionDiv").remove();
});

e、提取方法

JavaScript

/**
    根据输入值 显示问题项目 下拉框显示效果
*/
function selectProblemShow(inputVal){
		//先显示下拉框
   		$("#questionDiv").show();
		//获取全部数据
   	 	var li=$("#questionDiv").find("ul li");
		//没有数据时,不显示下拉框
		if(li && li.length==0){
			$("#questionDiv").hide();
		}
		//li的总数
		var totalli=li.length;
		//隐藏li的总数
		var hiddenLiCount=0;
		//遍历li
   	 	li.each(function(){
	   		 //问题内容
	   		 var questionContent=$(this).find("span").html();
	   		 //去除高亮标签
	   		 re1 = new RegExp("<b>","g"); 
	   		 re2 = new RegExp("</b>","g"); 
	   		 //获取原始内容
	   		 if(questionContent){
	   			 questionContent=questionContent.replace(re1,'').replace(re2,'')
	   		 }
	   		 //重新设置原始内容
	   		 $(this).find("span").html(questionContent);
	   		 //该项内容不包含输入的数据,隐藏该项
	   		 if(questionContent.indexOf(inputVal)==-1){
	   			 $(this).hide();
	   		 }else{
	   			 //该项内容包含输入的数据,显示该项
	   			 $(this).show();
	   			 //输入内容不为空时
	   			 if(inputVal){
	   				 //高亮显示
	       			 var values=questionContent.split(inputVal);
	   				 //填充数据
	       			 $(this).find("span").html(values.join("<b>"+inputVal+"</b>"));
	   			 }
	   		 }
	   		//如果元素隐藏,计数
   	 		 if($(this).is(':hidden')){
   	 			hiddenLiCount++;
   	 		 }
	   	 });
     	//全部隐藏,隐藏下拉框
   	 	if(totalli==hiddenLiCount){
   	 		$("#questionDiv").hide();
   	 	} 
}
 
 
/**
下拉框回写数据
*/
function selectProblemData($li,$textarea){
               //获取问题内容
	        var questionContent=$li.find("span").html();
    	 re1 = new RegExp("<b>","g"); 
		 re2 = new RegExp("</b>","g"); 
		 //处理高亮标签
		 if(questionContent){
			 questionContent=questionContent.replace(re1,'').replace(re2,'');
		 }
		 //严重程度
		 var severityLevel=$li.find("span").attr("severityLevel");
		 //设置内容
		 $textarea.val(questionContent);
		 //设置严重程度
		 $textarea.parent().next().find("div.dropdown").dropdown('set selected',severityLevel);
		 $("textArea").autoTextarea({
  			minHeight:28,
  			maxHeight:220,//文本框是否自动撑高,默认:null,不自动撑高;如果自动撑高必须输入数值,该值作为文本框自动撑高的最大高度
  		});
}


/**
递归获取下一个显示的li
*/
function getNextShowLi($li){
		//获取下一个元素
		var next=$li.next();
		//判断是隐藏
		if(next.is(":hidden")){
			//继续获取下一个元素
			next=getNextShowLi(next);
		}
		return next;
}
	
/**
递归获取上一个显示的li
*/
function getPrevShowLi($li){
		//获取上一个元素
		var prev=$li.prev();
		//判断是隐藏
		if(prev.is(":hidden")){
			//继续获取上一个元素
			prev=getPrevShowLi(prev);
		}
		return prev;
}

/**
 下拉框 向下选择 选择li超过可见区域时,滚动到li的位置
*/
function srollDownFun($li,firstFlag){
		//下拉框容器
		var container = $('#questionDiv');
		//下一行不是第一行,计算向下滚动
		if(!firstFlag){
			//获取可见区域li的绝对高度
			var tempTop=$li.offset().top - container.offset().top;
			//获取下拉框的高度
			var questionDivHeight=$("#questionDiv").innerHeight()+2;
			//判断可见区域最后一个li的绝对高度(包括本身的高度,取li的左下角的位置)大于下拉框高度
			if(tempTop+$li.height()>questionDivHeight){
				//滚动    -5(padding)
				container.animate({
				    scrollTop: $li.offset().top - container.offset().top + container.scrollTop()-5
				},0);
			}
		}else{
			//是第一行,重置滚动条位置
			container.animate({
			    scrollTop: 0
			},0);
		}
}
	
/**
下拉框 向上选择 选择li超过可见区域时,滚动到li的位置
*/
function srollUpFun($li,lastFlag){
		//下拉框容器
		var container = $('#questionDiv');
		//上一行不是最后一行,计算向上滚动
		if(!lastFlag){
			//下一个需要显示的li绝对高度  li的Y坐标-容器的Y坐标
			var tempTop=$li.offset().top - container.offset().top;
			//获取下拉框的高度
			var questionDivHeight=$("#questionDiv").innerHeight()+2;
			//当绝对高度小于0时 说明被遮挡了
			if(tempTop<0){
				//滚动  滚动条的高度减去 负的绝对高度  -5(padding)
				container.animate({
				    scrollTop: container.scrollTop()-(-tempTop)-5
				},0);
			}
		}else{
			//上一行是最后一行,滚动条滚动到底部
			var scrollHeight = $('#questionDiv').prop("scrollHeight");
			//滚动
			container.animate({
			    scrollTop: scrollHeight
			},0);
		}
}

 

四、效果

1、点击效果

image.png

2、模糊检索,高亮效果

image.png

3、方向键下 选择第一条效果

image.png

4、选择完成效果

image.png

5、点击回显效果

image.png

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值