本文实例为大家分享了js实现下拉框选择组件的具体代码,供大家参考,具体内容如下
功能需求:
1、点击div后,div显示聚焦状态,同时显示下拉框内容;
2、选择儿童人数后,如果儿童人数大于0,在下方出现对应的儿童年龄选择框数量;
3、成人人数的选择范围是1-7,儿童人数的选择范围是0-4,儿童年龄的选择范围是<1、1-17;
4、点击确认按钮后,将选择好的成人人数和儿童人数显示在最上方的div内;
5、可以控制选择框是否可点击;
6、当显示一个ul列表时,点击另一个ul列表,将上一个ul列表隐藏;
7、点击隐藏框内除绑定事件元素外,将正在显示的ul列表隐藏;
8、点击页面中任意空白位置,将显示的下拉框内容整体隐藏;
下拉框不可操作时的显示状态:
下拉框可操作时:
选择儿童人数后,下方自动出现对应数量的儿童年龄选择框:
点击确认按钮后,将结果显示在是上方的div内:
刚开始的想法是对select、ul下拉列表、btn按钮分别进行事件监听,此外还要有当点击下拉框内其它位置时,ul下拉列表隐藏、当点击body时整个下拉框内容隐藏。监听事件过多,而且事件冒泡也会影响事件的执行,导致某些事件会出现执行多次的情况。
儿童年龄的选择框是根据儿童的人数来生成的,有几个儿童,就有几个年龄选择框。这种情况下,年龄的选择框肯定是动态创建的,无法针对年龄的select进行事件监听,只能采用事件委托的形式,所以最后把对select、ul下拉列表、btn按钮的点击事件,还有当点击container内其它位置时,ul下拉列表隐藏。全部委托给了dropDownContainer元素。
下面附上代码
html结构代码:
<!DOCTYPE html> <html lang=\"en\"> <head> <meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"> <title>select</title> </head> <body> <script type=\"module\"> import Main from \'./js/Main.js\'; //参数为false时,选择框不可点击;为true时,选择框可使用 let main=new Main(true); main.appendTo(\"body\"); </script> </body> </html>
Main.js文件:
import Utils from \'./Utils.js\'; export default class Main{ static styles=false; listPrep; constructor(state){ //state控制下拉框是否可点击 this.state=state; this.elem=this.createE(); } createE(){ if(this.elem) return this.elem; let div=Utils.createE(\"div\"); div.className=\"guestsNum\"; div.innerHTML=`<span>人数未定</span><i></i> <div class=\"dropDownContainer none\" id=\"dropDownContainer\"> <div class=\"dropDownItem clearfix\"> <span>每间</span> <div class=\"dropDownSelect\"> <div class=\"dropDownCont\"><span id=\"adultNum\">2 成人</span><i></i></div> <ul class=\"dropDownList\" tag=\"adult\">${this.setDropDownList(\"adult\")}</ul> </div> <div class=\"dropDownSelect\"> <div class=\"dropDownCont\"><span id=\"childrenNum\">0 儿童</span><i></i></div> <ul class=\"dropDownList\" tag=\"children\"><li>0</li>${this.setDropDownList(\"children\")}</ul> </div> </div> <div class=\"dropDownItem clearfix none\" id=\"ItemAge\"></div> <div class=\"dropDownBottom clearfix\"> ${this.state?\'\':\'<em class=\"dropDownTips\">请优先选择日期,以便查询实时价格。</em>\'} ${this.state?\'<a class=\"dropDownBtn\" id=\"dropDownBtn\" href=\"javascript:void(0)\" rel=\"external nofollow\" rel=\"external nofollow\" >确认</a>\':\'<a class=\"dropDownBtn disabled\" href=\"javascript:void(0)\" rel=\"external nofollow\" rel=\"external nofollow\" >确认</a>\'} </div> </div>`; //设置样式,因为样式只设置一次就好,不需要实例化,所以使用静态方法 Main.setStyles(); //获取元素 Utils.getIdElem(div,this); //监听div的点击事件 div.addEventListener(\"click\",(e)=>this.guestsNumClickHandler(e)); //如果state为true,下拉框监听点击事件 if(this.state) this.dropDownContainer.addEventListener(\"click\",e=>this.dropDownContainerClick(e)); //document监听点击事件,隐藏下拉框 document.addEventListener(\"click\",e=>this.documentClick(e)); return div; } appendTo(parent){ Utils.appendTo(this.elem,parent); } guestsNumClickHandler(e){ //如果下拉框是显示状态,则直接跳出,避免重复操作 if(!Utils.hasClass(this.dropDownContainer,\"none\")) return; //如果点击的不是guestsNum,直接跳出,避免事件冒泡 if(e.target.nodeName!==\"SPAN\"&&e.target.nodeName!==\"I\"&&!Utils.hasClass(e.target,\"guestsNum\")) return; //给div添加聚集样式 Utils.addClass(this.elem,\"focus\"); //将dropDownContainer显示 Utils.removeClass(this.dropDownContainer,\"none\"); } dropDownContainerClick(e){ if(e.target.nodeName===\"LI\"){ //点击ul选择列表 this.dropDownListClick(e); } else if(e.target.id===\"dropDownBtn\"){ //点击确认按钮 this.dropDownBtnClick(); } else if(e.target.nodeName===\"SPAN\" || e.target.nodeName===\"I\") { //点击span或者i标签时,将它们的父元素div作为参数 this.dropDownSelectClick(e.target.parentElement); } else if(Utils.hasClass(e.target,\"dropDownCont\")){ //点击div选择框时,将div作为参数 this.dropDownSelectClick(e.target); } else { //点击下拉框内其它位置时,让当前的ul列表隐藏 if(this.listPrep) this.listPrep.style.display=\"none\"; } } dropDownSelectClick(div){ //隐藏掉上一个显示的ul列表 if(this.listPrep) this.listPrep.style.display=\"none\"; //当前点击的ul列表赋值给this.listPrep this.listPrep=div.nextElementSibling; //将当前点击的ul列表显示 this.listPrep.style.display=\"block\"; } dropDownListClick(e){ //获取当前点击的ul的tag属性值 let tag=this.listPrep.getAttribute(\"tag\"); let unit=\"\"; switch (tag){ case \"adult\": unit=\"成人\";break; case \"children\": unit=\"儿童\"; let txt=Number(e.target.innerText); //根据li的数值,自动创建下面的年龄选择框 this.setDropDownItemAge(txt); break; case \"age\": unit=\"岁\";break; } //将选择的li的值,显示出来 this.listPrep.previousElementSibling.firstElementChild.textContent=e.target.innerText+\" \"+unit; //显示完成后,将当前显示的ul隐藏 this.listPrep.style.display=\"none\"; } setDropDownItemAge(txt){ let str=\"<span>儿童年龄</span>\"; if(txt===0){ //如果是0,则年龄选择框不显示 this.ItemAge.style.display=\"none\"; }else{ this.ItemAge.style.display=\"block\"; //循环选择的数值,创建年龄选择框 for(let i=0;i<txt;i++){ str+=`<div class=\"dropDownSelect\"> <div class=\"dropDownCont\"><span><1岁</span><i></i></div> <ul class=\"dropDownList\" tag=\"age\"><li><1</li>${this.setDropDownList(\"age\")}</ul> </div>`; } this.ItemAge.innerHTML=str; } } dropDownBtnClick(){ //将选择的内容显示在最上方的select框内 let resultStr=this.adultNum.innerText.replace(/\\s/g,\"\")+\" \"+this.childrenNum.innerText.replace(/\\s/g,\"\"); this.elem.firstElementChild.textContent=resultStr; //隐藏dropDownContainer this.dropDownContainerHide(); } documentClick(e){ //避免事件冒泡 if(e.target!==document.documentElement && e.target!==document.body) return; //隐藏dropDownContainer this.dropDownContainerHide(); } dropDownContainerHide(){ //div去掉聚集状态 Utils.removeClass(this.elem,\"focus\"); //dropDownContainer隐藏 Utils.addClass(this.dropDownContainer,\"none\"); //隐藏当前显示的ul列表 if(this.listPrep) this.listPrep.style.display=\"none\"; } setDropDownList(type){ //创建ul下拉列表内容 let li=\"\"; let max=0; switch (type){ case \"adult\": max=8;break; case \"children\": max=5;break; case \"age\": max=18;break; } for(let i=1;i<max;i++){ li+=\"<li>\"+i+\"</li>\"; } return li; } static setStyles(){ if(Main.styles) return; Main.style=true; Utils.insertCss(\".guestsNum\",{ width:\"108px\", height:\"34px\", padding:\"0px 12px\", border:\"1px solid #ccc\", borderRadius:\"3px\", position:\"relative\", fontSize:\"14px\", color:\"#666\", userSelect:\"none\", }) Utils.insertCss(\".guestsNum.focus\",{ borderColor:\"#ffa800\", boxShadow:\"0 0 4px #ffa800\" }) Utils.insertCss(\".guestsNum>span\",{ lineHeight:\"34px\" }) Utils.insertCss(\".guestsNum>i\",{ display:\"inline-block\", width:\"16px\", height:\"16px\", backgroundImage:\"url(./image/user.jpg)\", float:\"right\", margin:\"8px 0px 0px 10px\" }) Utils.insertCss(\".dropDownContainer\",{ border: \"1px solid #ffa800\", borderRadius: \"4px\", boxShadow: \"0 0 4px #ffa800\", backgroundColor: \"#fff\", padding: \"20px 15px\", width: \"480px\", fontSize:\"12px\", position:\"absolute\", left:\"0px\", top:\"35px\", }) Utils.insertCss(\".dropDownItem\",{ marginBottom:\"12px\" }) Utils.insertCss(\".dropDownItem>span\",{ display:\"block\", width:\"60px\", lineHeight:\"28px\", float:\"left\", }) Utils.insertCss(\".dropDownSelect\",{ width:\"90px\", height:\"30px\", marginRight:\"10px\", float:\"left\", position:\"relative\" }) Utils.insertCss(\".dropDownCont\",{ border:\"1px solid #ccc\", borderRadius:\"3px\", height:\"12px\", padding:\"6px 8px 10px\", }) Utils.insertCss(\".dropDownCont>span\",{ display:\"inline-block\", width:\"53px\", height:\"14px\", lineHeight:\"14px\", borderRight:\"1px solid #ccc\" }) Utils.insertCss(\".dropDownCont>i\",{ display:\"inline-block\", width:\"0px\", height:\"0px\", border:\"5px solid #c6c6c6\", borderColor:\"#c6c6c6 transparent transparent\", margin: \"6px 0px 0px 4px\", float: \"right\" }) Utils.insertCss(\".dropDownList\",{ listStyle:\"none\", padding:\"0px\", margin:\"0px\", width:\"88px\", maxHeight:\"200px\", overflow:\"auto\", cursor:\"pointer\", border:\"1px solid #ccc\", backgroundColor:\"#fff\", borderRadius:\"4px\", position:\"absolute\", left:\"0px\", top:\"30px\", zIndex:\"2\", boxShadow: \"1px 1px 3px rgba(0,0,0,.1)\", display:\"none\" }) Utils.insertCss(\".dropDownList>li\",{ lineHeight:\"28px\", paddingLeft:\"8px\", }) Utils.insertCss(\".dropDownList>li:hover\",{ background:\"#f4f4f4\" }) Utils.insertCss(\".dropDownBottom\",{ borderTop:\"1px solid #ccc\", marginTop:\"20px\", paddingTop:\"20px\" }) Utils.insertCss(\".dropDownTips\",{ fontStyle:\"normal\", fontSize: \"12px\", color: \"#ef523d\", lineHeight:\"28px\" }) Utils.insertCss(\".dropDownBtn\",{ textDecoration:\"none\", float: \"right\", display: \"inline-block\", padding: \"2px 22px\", backgroundColor: \"#ffb200\", borderRadius: \"4px\", fontSize: \"14px\", lineHeight: \"24px\", color: \"#fff\", }) Utils.insertCss(\".dropDownBtn.disabled\",{ backgroundColor: \"#efefef\", color: \"#999\" }) Utils.insertCss(\".clearfix:after\",{ content:\"\\\".\\\"\", display:\"block\", overflow:\"hidden\", visibility:\"hidden\", clear:\"both\", height:\"0px\" }) Utils.insertCss(\".none\",{ display:\"none\" }) } }
Utils.js文件:
export default class Utils{ static createE(elem,style,prep){ elem=document.createElement(elem); if(style) for(let prop in style) elem.style[prop]=style[prop]; if(prep) for(let prop in prep) elem[prop]=prep[prop]; return elem; } static appendTo(elem,parent){ if (parent.constructor === String) parent = document.querySelector(parent); parent.appendChild(elem); } static randomNum(min,max){ return Math.floor(Math.random*(max-min)+min); } static randomColor(alpha){ alpha=alpha||Math.random().toFixed(1); if(isNaN(alpha)) alpha=1; if(alpha>1) alpha=1; if(alpha<0) alpha=0; let col=\"rgba(\"; for(let i=0;i<3;i++){ col+=Utils.randomNum(0,256)+\",\"; } col+=alpha+\")\"; return col; } static insertCss(select,styles){ if(document.styleSheets.length===0){ let styleS=Utils.createE(\"style\"); Utils.appendTo(styleS,document.head); } let styleSheet=document.styleSheets[document.styleSheets.length-1]; let str=select+\"{\"; for(var prop in styles){ str+=prop.replace(/[A-Z]/g,function(item){ return \"-\"+item.toLocaleLowerCase(); })+\":\"+styles[prop]+\";\"; } str+=\"}\" styleSheet.insertRule(str,styleSheet.cssRules.length); } static getIdElem(elem,obj){ if(elem.id) obj[elem.id]=elem; if(elem.children.length===0) return obj; for(let i=0;i<elem.children.length;i++){ Utils.getIdElem(elem.children[i],obj); } } static addClass(elem,className){ let arr=(elem.className+\" \"+className).match(/\\S+/g); arr=arr.filter((item,index)=>arr.indexOf(item,index+1)<0) elem.className=arr.join(\" \"); } static removeClass(elem,className){ if(!elem.className) return; let arr=elem.className.match(/\\S+/g); let arr1=className.match(/\\S+/g); arr1.forEach(item=>{ arr=arr.filter(t=>t!==item) }) elem.className=arr.join(\" \"); } static hasClass(elem,className){ if(!elem.className) return false; let arr=elem.className.match(/\\S+/g); let arr1=className.match(/\\S+/g); let res; arr1.forEach(item=>{ res= arr.some(it=>it===item) }) return res; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
暂无评论内容