本文实例为大家分享了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结构代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!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文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
|
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文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
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