本文實例為大家分享了js實現下拉框選擇組件的具體代碼,供大家參考,具體內容如下
功能需求:
1、點擊div后,div顯示聚焦狀態(tài),同時顯示下拉框內容;
2、選擇兒童人數后,如果兒童人數大于0,在下方出現對應的兒童年齡選擇框數量;
3、成人人數的選擇范圍是1-7,兒童人數的選擇范圍是0-4,兒童年齡的選擇范圍是<1、1-17;
4、點擊確認按鈕后,將選擇好的成人人數和兒童人數顯示在最上方的div內;
5、可以控制選擇框是否可點擊;
6、當顯示一個ul列表時,點擊另一個ul列表,將上一個ul列表隱藏;
7、點擊隱藏框內除綁定事件元素外,將正在顯示的ul列表隱藏;
8、點擊頁面中任意空白位置,將顯示的下拉框內容整體隱藏;
下拉框不可操作時的顯示狀態(tài):
下拉框可操作時:
選擇兒童人數后,下方自動出現對應數量的兒童年齡選擇框:
點擊確認按鈕后,將結果顯示在是上方的div內:
剛開始的想法是對select、ul下拉列表、btn按鈕分別進行事件監(jiān)聽,此外還要有當點擊下拉框內其它位置時,ul下拉列表隱藏、當點擊body時整個下拉框內容隱藏。監(jiān)聽事件過多,而且事件冒泡也會影響事件的執(zhí)行,導致某些事件會出現執(zhí)行多次的情況。
兒童年齡的選擇框是根據兒童的人數來生成的,有幾個兒童,就有幾個年齡選擇框。這種情況下,年齡的選擇框肯定是動態(tài)創(chuàng)建的,無法針對年齡的select進行事件監(jiān)聽,只能采用事件委托的形式,所以最后把對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">請優(yōu)先選擇日期,以便查詢實時價格。</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>`; //設置樣式,因為樣式只設置一次就好,不需要實例化,所以使用靜態(tài)方法 Main.setStyles(); //獲取元素 Utils.getIdElem(div, this ); //監(jiān)聽div的點擊事件 div.addEventListener( "click" ,(e)=> this .guestsNumClickHandler(e)); //如果state為true,下拉框監(jiān)聽點擊事件 if ( this .state) this .dropDownContainer.addEventListener( "click" ,e=> this .dropDownContainerClick(e)); //document監(jiān)聽點擊事件,隱藏下拉框 document.addEventListener( "click" ,e=> this .documentClick(e)); return div; } appendTo(parent){ Utils.appendTo( this .elem,parent); } guestsNumClickHandler(e){ //如果下拉框是顯示狀態(tài),則直接跳出,避免重復操作 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的數值,自動創(chuàng)建下面的年齡選擇框 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" ; //循環(huán)選擇的數值,創(chuàng)建年齡選擇框 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去掉聚集狀態(tài) Utils.removeClass( this .elem, "focus" ); //dropDownContainer隱藏 Utils.addClass( this .dropDownContainer, "none" ); //隱藏當前顯示的ul列表 if ( this .listPrep) this .listPrep.style.display= "none" ; } setDropDownList(type){ //創(chuàng)建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