原生js实现下拉框选择组件

本文实例为大家分享了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;

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 原生js实现下拉框选择组件 的全部内容, 来源链接: utcz.com/p/219431.html

回到顶部