本文实例为大家分享了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;
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/Charissa2017/article/details/104111603