原生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、点击页面中任意空白位置,将显示的下拉框内容整体隐藏;

下拉框不可操作时的显示状态:

原生js实现下拉框选择组件_第1张图片

下拉框可操作时:

原生js实现下拉框选择组件_第2张图片

选择儿童人数后,下方自动出现对应数量的儿童年龄选择框:

原生js实现下拉框选择组件_第3张图片

点击确认按钮后,将结果显示在是上方的div内:

刚开始的想法是对select、ul下拉列表、btn按钮分别进行事件监听,此外还要有当点击下拉框内其它位置时,ul下拉列表隐藏、当点击body时整个下拉框内容隐藏。监听事件过多,而且事件冒泡也会影响事件的执行,导致某些事件会出现执行多次的情况。

儿童年龄的选择框是根据儿童的人数来生成的,有几个儿童,就有几个年龄选择框。这种情况下,年龄的选择框肯定是动态创建的,无法针对年龄的select进行事件监听,只能采用事件委托的形式,所以最后把对select、ul下拉列表、btn按钮的点击事件,还有当点击container内其它位置时,ul下拉列表隐藏。全部委托给了dropDownContainer元素。

下面附上代码

html结构代码:




  
  
  select


  

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=`人数未定
    `;
    //设置样式,因为样式只设置一次就好,不需要实例化,所以使用静态方法
    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="儿童年龄";
    if(txt===0){
      //如果是0,则年龄选择框不显示
      this.ItemAge.style.display="none";
    }else{
      this.ItemAge.style.display="block";
      //循环选择的数值,创建年龄选择框
      for(let i=0;i
        
        
      
`; } 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"; } 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;iarr.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实现下拉框选择组件)