好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

原生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;

   }

}

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

原文链接:https://blog.csdn.net/Charissa2017/article/details/104111603

查看更多关于原生js实现下拉框选择组件的详细内容...

  阅读:44次