本實例開發的級聯下拉菜單是根據已有json數據創建的DOM元素。點擊文本框后,顯示一級菜單。如果菜單中包含子菜單,菜單右側會有指示箭頭。點擊菜單之后,會再顯示下一級菜單,以此類推。當菜單下無子菜單時,選擇菜單后會在文本框中顯示。
打開后的級聯菜單效果如圖所示:
使用實例中封裝好的插件,只需要有一個input元素,即可通過插件自動生成級聯下拉菜單,html代碼如下所示:
1
2
3
|
< div style = "margin-top:100px;text-align:center;" > < input type = "text" id = "input" > </ div > |
接下來看下具體封裝的js代碼怎么實現。
1. 聲明級聯菜單的構造函數
構造函數需要傳入一個文本框元素和菜單關聯數據兩個參數。
1
2
3
4
|
//elem為文本框,data為菜單關聯數據 function CascadeMenu(elem,data){ } |
2. 在構造函數中創建級聯菜單相關元素,并放到頁面中,具體代碼如下:
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
|
function CascadeMenu(elem,data){ //獲取文本框 this .eInput = elem; //設置文本框為只讀 this .eInput.setAttribute( 'readonly' , true ); //設置文本框提示 this .eInput.placeholder = '請選擇' ; //獲取文本框父元素 var eInputParent = this .eInput.parentNode; //創建級聯菜單容器 this .eCascade = document.createElement( 'div' ); this .eCascade.className = 'cascade_container' ; //創建菜單下拉列表容器 this .eCascadeInto = document.createElement( 'div' ); this .eCascadeInto.className = 'cascade_into' ; //下拉列表容器默認隱藏 this .eCascadeInto.style.display = 'none' ; //將各個元素放到頁面中 this .eCascade.appendChild( this .eInput); this .eCascade.appendChild( this .eCascadeInto); eInputParent.appendChild( this .eCascade); //獲取菜單數據 this .aData = data; //記錄已選擇的菜單數據 this .aSelected = []; //菜單打開狀態,默認為false,表示隱藏 this .bShow = false ; } |
3. 在文本框上綁定點擊事件,生成級聯下拉菜單
剛才已經把需要的元素都放到了頁面中,現在可以通過點擊文本框顯示和隱藏級聯菜單元素;
在顯示級聯菜單元素時,應該要通過數據生成級聯下拉菜單。
因為每次點擊都需要生成,所以可以在構造函數的原型上添加一個方法。如下所示:
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
|
function CascadeMenu(elem,data){ /*…*/ this .eInput.addEventListener( 'click' ,()=>{ //判斷菜單打開狀態 if ( this .bShow){ //如果已打開,則隱藏菜單 this .eCascadeInto.style.display = 'none' ; //修改菜單打開狀態 this .bShow = false ; } else { //顯示級聯菜單元素 this .eCascadeInto.style.display = 'none' ; //保存已選擇的菜單數據 this .aSelected = this .eInput.value.split( '>' ); //生成級聯菜單 this .generateMenu(); } }); } //根據數據生成級聯菜單 CascadeMenu.prototype.generateMenu = function (){ //在fnCreatHTML調用實例對象需要聲明一個變量指向this var _self = this ; //因為不確定子菜單有多少組,所以需要聲明一個函數來遞歸調用 //data:傳入數據,step:當前級別 function fnCreatHTML(data,step){ //用于存儲子菜單數據 var aChildArr = null ; //生成菜單DOM的字符串 var sHTML = '<ul>' ; //循環數據 for (let i=0;i<data.length;i++){ //判斷如果有子菜單,添加child的class,用于顯示菜單右側箭頭 if (data[i].child){ //判斷是否是當前選擇,如果是,加上cur class,并且存儲子菜單數據 if (data[i].name== this .aSelected[step]){ aChildArr = data[i].child; sHTML += '<li class="child cur" data-po="' +step+ '">' ; } else { sHTML += '<li class="child" data-po="' +step+ '">' ; } } else { //如果沒有子菜單,直接加到菜單列表中 sHTML += data[i].name == this .aSelected[step]? '<li class="cur" data-po="' +step+ '">' : '<li data-po="' +step+ '">' ; } //添加菜單名稱 sHTML += data[i].name; //結束當前菜單 sHTML += '</li>' ; } sHTML += '</ul>' ; //如果已選擇多個菜單,遞歸調用函數,生成子菜單 if ( this .aSelected.length>step+1){ sHTML += fnCreatHTML(aChildArr,step+1); } return sHTML; } this .eCascadeInto.innerHTML = fnCreatHTML( this .aData,0); } |
4. 菜單上綁定事件,用于選擇菜單
級聯菜單有兩種類型,一種是有下級菜單的,點擊時顯示下級菜單;
一種是沒有下級菜單的,點擊時直接選擇菜單并在文本框中按級別顯示所選擇的菜單。代碼如下所示:
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
|
function CascadeMenu(elem,data){ /*…*/ //利用事件委托選擇菜單 this .eCascadeInto.addEventListener( 'click' ,(event)=>{ //獲取菜單 var eTarget = event.target; //獲取選擇的級別 var po = +eTarget.dataset.po; //刪除當前選擇級后面的數據 this .aSelected.splice(po+1, this .aSelected.length-(po+1)); //修改當前選擇數據 this .aSelected[po] = eTarget.innerHTML; //判斷是否有子菜單 if (eTarget.className.indexOf( 'child' )==-1){ //沒有子菜單直接選擇 this .eInput.value = this .aSelected.join( '>' ); this .eCascadeInto.style.display = 'none' ; this .bShow = false ; } else { //有子菜單顯示下一級 //重新生成DOM元素,數組中增加空字符串用于顯示下一級 this .aSelected.push( '' ) //重新生成級聯菜單 this .generateMenu(); } }); } |
5. 在頁面空白處點擊時,隱藏菜單
現在只能在文本框上點擊顯示和隱藏菜單。一般來說任何打開的彈框,都希望在彈框以外的位置可以關閉掉。這樣需要修改一下文本框上的點擊事件函數:當打開菜單時,要在document元素上綁定點擊事件,用于關閉菜單;當隱藏菜單時,需要取消document上綁定的點擊事件。如下所示:
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
|
function CascadeMenu(elem,data){ /*…*/ this .eInput.addEventListener( 'click' ,()=>{ //判斷菜單打開狀態 if ( this .bShow){ //如果已打開,則隱藏菜單 this .eCascadeInto.style.display = 'none' ; //修改菜單打開狀態 this .bShow = false ; //取消document上的事件 document.onclick = null ; } else { //顯示級聯菜單元素 this .eCascadeInto.style.display = 'none' ; //保存已選擇的菜單數據 this .aSelected = this .eInput.value.split( '>' ); //生成級聯菜單 this .generateMenu(); document.onclick = () => { //隱藏菜單 this .eCascadeInto.style.display = 'none' ; //修改菜單打開狀態 this .bShow = false ; //取消document上的事件 document.onclick = null ; } } }); //阻止冒泡 this .eCascade.addEventListener( 'click' ,(event)=>{ event.stopPropagation(); }); /*…*/ } |
6. 最后,準備好數據,調用構造函數,生成級聯下拉菜單,如下所示:
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
|
var json = [ { "name" : "北京市" , "id" : "110000" , "child" :[ { "name" : "市轄區" , "id" : "110100" , "child" :[ { "name" : "東城區" , "id" : "110101" , "child" : null },{ "name" : "西城區" , "id" : "110102" , "child" : null },{ "name" : "朝陽區" , "id" : "110105" , "child" : null },{ "name" : "豐臺區" , "id" : "110106" , "child" : null },{ "name" : "石景山區" , "id" : "110107" , "child" : null },{ "name" : "海淀區" , "id" : "110108" , "child" : null },{ "name" : "門頭溝區" , "id" : "110109" , "child" : null },{ "name" : "房山區" , "id" : "110111" , "child" : null },{ "name" : "通州區" , "id" : "110112" , "child" : null },{ "name" : "順義區" , "id" : "110113" , "child" : null },{ "name" : "昌平區" , "id" : "110114" , "child" : null },{ "name" : "大興區" , "id" : "110115" , "child" : null },{ "name" : "懷柔區" , "id" : "110116" , "child" : null },{ "name" : "平谷區" , "id" : "110117" , "child" : null },{ "name" : "密云區" , "id" : "110118" , "child" : null },{ "name" : "延慶區" , "id" : "110119" , "child" : null }] }, { "name" : "北京市" , "id" : "110000" , "child" : null } ] }, { "name" : "河北省" , "id" : "130000" , "child" :[ { "name" : "石家莊市" , "id" : "130100" , "child" :[ { "name" : "市轄區" , "id" : "130101" , "child" : null },{ "name" : "長安區" , "id" : "130102" , "child" : null },{ "name" : "橋西區" , "id" : "130104" , "child" : null },{ "name" : "新華區" , "id" : "130105" , "child" : null },{ "name" : "井陘礦區" , "id" : "130107" , "child" : null },{ "name" : "裕華區" , "id" : "130108" , "child" : null },{ "name" : "藁城區" , "id" : "130109" , "child" : null },{ "name" : "鹿泉區" , "id" : "130110" , "child" : null },{ "name" : "欒城區" , "id" : "130111" , "child" : null },{ "name" : "井陘縣" , "id" : "130121" , "child" : null },{ "name" : "正定縣" , "id" : "130123" , "child" : null },{ "name" : "行唐縣" , "id" : "130125" , "child" : null },{ "name" : "靈壽縣" , "id" : "130126" , "child" : null },{ "name" : "高邑縣" , "id" : "130127" , "child" : null },{ "name" : "深澤縣" , "id" : "130128" , "child" : null },{ "name" : "贊皇縣" , "id" : "130129" , "child" : null },{ "name" : "無極縣" , "id" : "130130" , "child" : null },{ "name" : "平山縣" , "id" : "130131" , "child" : null },{ "name" : "元氏縣" , "id" : "130132" , "child" : null },{ "name" : "趙縣" , "id" : "130133" , "child" : null },{ "name" : "晉州市" , "id" : "130183" , "child" : null },{ "name" : "新樂市" , "id" : "130184" , "child" : null }] }, { "name" : "唐山市" , "id" : "130200" , "child" :[ { "name" : "市轄區" , "id" : "130201" , "child" : null },{ "name" : "路南區" , "id" : "130202" , "child" : null },{ "name" : "路北區" , "id" : "130203" , "child" : null },{ "name" : "古冶區" , "id" : "130204" , "child" : null },{ "name" : "開平區" , "id" : "130205" , "child" : null },{ "name" : "豐南區" , "id" : "130207" , "child" : null },{ "name" : "豐潤區" , "id" : "130208" , "child" : null },{ "name" : "曹妃甸區" , "id" : "130209" , "child" : null },{ "name" : "灤縣" , "id" : "130223" , "child" : null },{ "name" : "灤南縣" , "id" : "130224" , "child" : null },{ "name" : "樂亭縣" , "id" : "130225" , "child" : null },{ "name" : "遷西縣" , "id" : "130227" , "child" : null },{ "name" : "玉田縣" , "id" : "130229" , "child" : null },{ "name" : "遵化市" , "id" : "130281" , "child" : null },{ "name" : "遷安市" , "id" : "130283" , "child" : null }] }, { "name" : "秦皇島市" , "id" : "130300" , "child" :[ { "name" : "市轄區" , "id" : "130301" , "child" : null },{ "name" : "海港區" , "id" : "130302" , "child" : null },{ "name" : "山海關區" , "id" : "130303" , "child" : null },{ "name" : "北戴河區" , "id" : "130304" , "child" : null },{ "name" : "撫寧區" , "id" : "130306" , "child" : null },{ "name" : "青龍滿族自治縣" , "id" : "130321" , "child" : null },{ "name" : "昌黎縣" , "id" : "130322" , "child" : null },{ "name" : "盧龍縣" , "id" : "130324" , "child" : null }] }, { "name" : "邯鄲市" , "id" : "130400" , "child" :[ { "name" : "市轄區" , "id" : "130401" , "child" : null },{ "name" : "邯山區" , "id" : "130402" , "child" : null },{ "name" : "叢臺區" , "id" : "130403" , "child" : null },{ "name" : "復興區" , "id" : "130404" , "child" : null },{ "name" : "峰峰礦區" , "id" : "130406" , "child" : null },{ "name" : "邯鄲縣" , "id" : "130421" , "child" : null },{ "name" : "臨漳縣" , "id" : "130423" , "child" : null },{ "name" : "成安縣" , "id" : "130424" , "child" : null },{ "name" : "大名縣" , "id" : "130425" , "child" : null },{ "name" : "涉縣" , "id" : "130426" , "child" : null },{ "name" : "磁縣" , "id" : "130427" , "child" : null },{ "name" : "肥鄉縣" , "id" : "130428" , "child" : null },{ "name" : "永年縣" , "id" : "130429" , "child" : null },{ "name" : "邱縣" , "id" : "130430" , "child" : null },{ "name" : "雞澤縣" , "id" : "130431" , "child" : null },{ "name" : "廣平縣" , "id" : "130432" , "child" : null },{ "name" : "館陶縣" , "id" : "130433" , "child" : null },{ "name" : "魏縣" , "id" : "130434" , "child" : null },{ "name" : "曲周縣" , "id" : "130435" , "child" : null },{ "name" : "武安市" , "id" : "130481" , "child" : null }] } ] }, { "name" : "湖南省" , "id" : "430000" , "child" :[ { "name" : "長沙市" , "id" : "430100" , "child" :[ { "name" : "市轄區" , "id" : "430101" , "child" : null },{ "name" : "芙蓉區" , "id" : "430102" , "child" : null },{ "name" : "天心區" , "id" : "430103" , "child" : null },{ "name" : "岳麓區" , "id" : "430104" , "child" : null },{ "name" : "開福區" , "id" : "430105" , "child" : null },{ "name" : "雨花區" , "id" : "430111" , "child" : null },{ "name" : "望城區" , "id" : "430112" , "child" : null },{ "name" : "長沙縣" , "id" : "430121" , "child" : null },{ "name" : "寧鄉縣" , "id" : "430124" , "child" : null },{ "name" : "瀏陽市" , "id" : "430181" , "child" : null }] }, { "name" : "株洲市" , "id" : "430200" , "child" :[ { "name" : "市轄區" , "id" : "430201" , "child" : null },{ "name" : "荷塘區" , "id" : "430202" , "child" : null },{ "name" : "蘆淞區" , "id" : "430203" , "child" : null },{ "name" : "石峰區" , "id" : "430204" , "child" : null },{ "name" : "天元區" , "id" : "430211" , "child" : null },{ "name" : "株洲縣" , "id" : "430221" , "child" : null },{ "name" : "攸縣" , "id" : "430223" , "child" : null },{ "name" : "茶陵縣" , "id" : "430224" , "child" : null },{ "name" : "炎陵縣" , "id" : "430225" , "child" : null },{ "name" : "醴陵市" , "id" : "430281" , "child" : null }] }, { "name" : "湘潭市" , "id" : "430300" , "child" :[ { "name" : "市轄區" , "id" : "430301" , "child" : null },{ "name" : "雨湖區" , "id" : "430302" , "child" : null },{ "name" : "岳塘區" , "id" : "430304" , "child" : null },{ "name" : "湘潭縣" , "id" : "430321" , "child" : null },{ "name" : "湘鄉市" , "id" : "430381" , "child" : null },{ "name" : "韶山市" , "id" : "430382" , "child" : null }] }, { "name" : "衡陽市" , "id" : "430400" , "child" :[ { "name" : "市轄區" , "id" : "430401" , "child" : null },{ "name" : "珠暉區" , "id" : "430405" , "child" : null },{ "name" : "雁峰區" , "id" : "430406" , "child" : null },{ "name" : "石鼓區" , "id" : "430407" , "child" : null },{ "name" : "蒸湘區" , "id" : "430408" , "child" : null },{ "name" : "南岳區" , "id" : "430412" , "child" : null },{ "name" : "衡陽縣" , "id" : "430421" , "child" : null },{ "name" : "衡南縣" , "id" : "430422" , "child" :[ { "name" : "三塘鎮" ,id: "430422" ,child: null },{ "name" : "車江鎮" ,id: "430422" ,child: null } ]},{ "name" : "衡山縣" , "id" : "430423" , "child" : null },{ "name" : "衡東縣" , "id" : "430424" , "child" : null },{ "name" : "祁東縣" , "id" : "430426" , "child" : null },{ "name" : "耒陽市" , "id" : "430481" , "child" : null },{ "name" : "常寧市" , "id" : "430482" , "child" : null }] } ] }, { "name" : "廣東省" , "id" : "440000" , "child" :[ { "name" : "廣州市" , "id" : "440100" , "child" :[ { "name" : "市轄區" , "id" : "440101" , "child" : null },{ "name" : "荔灣區" , "id" : "440103" , "child" : null },{ "name" : "越秀區" , "id" : "440104" , "child" : null },{ "name" : "海珠區" , "id" : "440105" , "child" : null },{ "name" : "天河區" , "id" : "440106" , "child" : null },{ "name" : "白云區" , "id" : "440111" , "child" : null },{ "name" : "黃埔區" , "id" : "440112" , "child" : null },{ "name" : "番禺區" , "id" : "440113" , "child" : null },{ "name" : "花都區" , "id" : "440114" , "child" : null },{ "name" : "南沙區" , "id" : "440115" , "child" : null },{ "name" : "從化區" , "id" : "440117" , "child" : null },{ "name" : "增城區" , "id" : "440118" , "child" : null }] }, { "name" : "韶關市" , "id" : "440200" , "child" :[ { "name" : "市轄區" , "id" : "440201" , "child" : null },{ "name" : "武江區" , "id" : "440203" , "child" : null },{ "name" : "湞江區" , "id" : "440204" , "child" : null },{ "name" : "曲江區" , "id" : "440205" , "child" : null },{ "name" : "始興縣" , "id" : "440222" , "child" : null },{ "name" : "仁化縣" , "id" : "440224" , "child" : null },{ "name" : "翁源縣" , "id" : "440229" , "child" : null },{ "name" : "乳源瑤族自治縣" , "id" : "440232" , "child" : null },{ "name" : "新豐縣" , "id" : "440233" , "child" : null },{ "name" : "樂昌市" , "id" : "440281" , "child" : null },{ "name" : "南雄市" , "id" : "440282" , "child" : null }] }, { "name" : "深圳市" , "id" : "440300" , "child" :[ { "name" : "市轄區" , "id" : "440301" , "child" : null },{ "name" : "羅湖區" , "id" : "440303" , "child" : null },{ "name" : "福田區" , "id" : "440304" , "child" : null },{ "name" : "南山區" , "id" : "440305" , "child" : null },{ "name" : "寶安區" , "id" : "440306" , "child" : null },{ "name" : "龍崗區" , "id" : "440307" , "child" : null },{ "name" : "鹽田區" , "id" : "440308" , "child" : null }] }, { "name" : "珠海市" , "id" : "440400" , "child" :[ { "name" : "市轄區" , "id" : "440401" , "child" : null },{ "name" : "香洲區" , "id" : "440402" , "child" : null },{ "name" : "斗門區" , "id" : "440403" , "child" : null },{ "name" : "金灣區" , "id" : "440404" , "child" : null }] } ] }, { "name" : "南沙群島" , "id" : "900001" , "child" : null } ]; var eText = document.getElementById( 'input' ); new CascadeMenu(eText,json); |
一個封裝好的js級聯下拉功能就完成了,可以根據圖片自己編寫css樣式以達到需要的效果。
以上就是js面向對象封裝級聯下拉菜單列表的實現步驟的詳細內容,更多關于js 封裝下拉菜單的資料請關注服務器之家其它相關文章!
原文鏈接:https://www.cnblogs.com/jiangweiping/p/14386548.html