一、需求
需要创建一个常见问题库,填写存在问题时可以下拉选择,可以模糊搜索,也可以手写。如果选择了问题库中的内容,自动填充内容到存在问题中,并且自动选择严重程度,最终保存的值还是界面显示的内容。
二、可行性研究
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 默认隐藏 用于缓存数据
<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、页面结构
td中一个textarea
4、界面样式
.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、文本域点击事件
//输入框点击事件 $("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、文本框输入内容
//监听文本框输入内容 $(".deductCheckInfo textarea").on("input propertychange",function(e){ //获取当前输入内容 var curText=$(this).val(); //下拉框内容检索和显示 selectProblemShow(curText); });
c、监听键盘按键
//监听文本框键盘按键 $(".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、空白处点击事件
//点击空白处隐藏删除下拉框 $(document).click(function(e){ $("#questionDiv").remove(); });
e、提取方法
/** 根据输入值 显示问题项目 下拉框显示效果 */ 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、点击效果
2、模糊检索,高亮效果
3、方向键下 选择第一条效果
4、选择完成效果
5、点击回显效果
还没有评论,来说两句吧...