類(lèi)似的多級浮動(dòng)菜單網(wǎng)上也很多實(shí)例,但大部分都是只針對一種情況或不夠靈活,簡(jiǎn)單說(shuō)就是做死了的。
所以我就想到做一個(gè)能夠自定義菜單的,有更多功能的多級浮動(dòng)菜單。
而其中的關(guān)鍵就是怎么根據自定義的菜單結構來(lái)生成新菜單,
關(guān)鍵中的難點(diǎn)就是怎么得到下級菜單結構和容器對象的使用。
理想的做法是每次有下級菜單時(shí),從對象直接取得下級菜單結構,放到容器對象中,
并且容器能重用,而不是每次都重新生成。
但想了很久也想不到適合的做法,直到做了多級聯(lián)動(dòng)下拉菜單終于得到了靈感。
放棄了直接取得下級菜單結構,而是每次都從原來(lái)的菜單結構中獲取當前需要的下級菜單結構。
容器對象也不是自動(dòng)生成,而是由用戶(hù)先定義好(后來(lái)也做到能自動(dòng)生成了)。
放下了這些包袱后,后面的開(kāi)發(fā)就順暢了。
特點(diǎn):
1.根據自定義菜單結構生成菜單;
2.多級聯(lián)動(dòng)功能;
3.自定義浮動(dòng)位置(上下左右);
4.自定義延遲效果;
5.js控制編輯菜單;
6.可根據需要自動(dòng)生產(chǎn)容器對象;
效果:
程序原理(建議參照代碼閱讀):
程序是根據傳統浮動(dòng)菜單擴展而來(lái),這里說(shuō)一下幾個(gè)比較關(guān)鍵或有用的地方:
【延時(shí)功能】這個(gè)很多人都懂,就是設個(gè)setTimeout計時(shí)器,這里有兩個(gè)計時(shí)器,分別是容器計時(shí)器和菜單計時(shí)器。
容器計時(shí)器的作用是鼠標移到容器外面時(shí)隱藏容器,難點(diǎn)是如何判斷當前鼠標是不是在容器外面。
一般的方法是設個(gè)bool參數,mouseout時(shí)設為false,mouseover時(shí)設為true(or倒過(guò)來(lái)),再根據這個(gè)參數判斷,
但這個(gè)方法在這個(gè)不行,經(jīng)過(guò)容器里的菜單對象時(shí)會(huì )觸發(fā)容器mouseout,
由于事件冒泡,菜單對象的mouseout也會(huì )觸發(fā)容器的mouseout。
例如:

這里推薦一個(gè)方法,使用contains(ff是compareDocumentPosition)方法。
這個(gè)方法是我做圖片滑動(dòng)展示效果時(shí)muxrwc教我的:
Each(oThis.Container, function(o, i){ if(o.contains ? o.contains(oT) || o == oT : o.compareDocumentPosition(oT) & 16){ isIn = true; } });
詳細參考仿LightBox內容顯示效果,而菜單計時(shí)器就沒(méi)什么特別,就是用來(lái)設置菜單內容。
【浮動(dòng)位置】除了母菜單的容器是固定的,子菜單的容器都是絕對定位的,定位的關(guān)鍵就是取得適合的left和top值。
首先要取得上一級菜單的left和top值。
由于母菜單是相對定位的,要取它的絕對left和top值就必須逐層向上取值,并加起來(lái):
取得上一級菜單的left和top值后,再進(jìn)行相應的移位就可以了:

這里要注意,如果display為none的話(huà)會(huì )取不到offset值,
所以為了在隱藏的狀態(tài)也能定位,就要用visibility來(lái)隱藏。
當然如果display可以先顯示再定位,但這樣會(huì )出現瞬間移動(dòng)的現象,不建議。
【自動(dòng)生成容器對象】
除了第一個(gè)容器對象,當發(fā)現容器不夠時(shí),會(huì )根據前一個(gè)容器來(lái)生成新容器。
開(kāi)始時(shí)我想用cloneNode,但由于對象中有事件所以不能這樣用,只能手動(dòng)建一個(gè)。
為了使用相同的樣式,復制cssText(這個(gè)也是muxrwc告訴我的)和className到新容器,
然后用IniContainer()函數設置一下就可以了:

【多級聯(lián)動(dòng)】
多級聯(lián)動(dòng)的關(guān)鍵是如何得到子菜單結構和根據這個(gè)子菜單結構生成菜單對象。
先說(shuō)說(shuō)菜單結構,是類(lèi)似這樣的結構:

知道json的應該都知道是什么了,js的一種對象結構:
txt是顯示的內容,也可以是html,到時(shí)會(huì )innerHTML插入;
position是位置,可以是"right"(默認),"down","up","left",浮動(dòng)位置會(huì )根據這個(gè)值來(lái)設置;
menu是下一級的菜單結構。
可以看出這類(lèi)似一個(gè)n維數組,注意是類(lèi)似。
那怎么根據這個(gè)菜單結構獲得當前菜單的子菜單呢?
首先從菜單對象的onmouseover說(shuō)起,
在菜單a的onmouseover中,要做的是重新設置菜單和重新設置樣式(這個(gè)稍后再說(shuō))。
設置菜單還包括設置一個(gè)索引屬性index來(lái)記錄當前容器菜單的索引(容器第幾個(gè)菜單),
這里有點(diǎn)取巧的是容器菜單的索引跟對應菜單結構中menu的索引是相同的(后面會(huì )用到),
而_index是當前容器的索引(第幾個(gè)容器),同樣這里的索引也可以用來(lái)指示當前菜單在第幾級。
還要設置_onmenu為當前的菜單對象,它在取浮動(dòng)位置時(shí)需要用到。
然后就可以用Set()程序來(lái)設置菜單了:

在Set()程序中第一部是先隱藏select,這是通用的做法了:
設置一個(gè)參數,作為容器集合的索引,這里可以直接從第二級開(kāi)始,所以設i初始值為1。
用一個(gè)while來(lái)反復取子菜單結構(menu),直到?jīng)]有子菜單(menu長(cháng)度為0)或者取得了子菜單結構(_index==i)。
這里沒(méi)有用for,因為我覺(jué)得while比較合適,或者for更好也說(shuō)不定。
這里除了取得子菜單結構也要取得子菜單的定位(position)。
期間如果容器不夠會(huì )自動(dòng)添加。
取得了子菜單結構和定位后,就可以用SetContainer()設置下一級菜單容器了:

程序SetContainer()用的技巧不多,首先對容器進(jìn)行相關(guān)設置,在使用了SetMenu()來(lái)設置菜單對象,
然后是容器的定位和顯示,最后隱藏不需要的容器,這部分就不說(shuō)明了。
要說(shuō)說(shuō)的是SetMenu()程序,它的作用是根據菜單結構設置菜單對象并放到容器中。
根據菜單結構的每個(gè)元素創(chuàng )建一個(gè)菜單對象,innerHTML元素的txt屬性,設置mouseover事件,最后appendChild到容器中。
這里比較重要的是mouseover事件,在mouseover事件中會(huì )重新設置菜單和重新設置樣式,
當觸發(fā)mouseover事件就回到一開(kāi)頭的“從菜單對象的onmouseover說(shuō)起”(輪回!-_-)。
不知你暈不暈,反正剛開(kāi)始時(shí)我是比較暈的了。
【焦點(diǎn)樣式設置】
這里說(shuō)的就是SetMenu()中重新設置樣式的部分。
程序中可以看出鼠標指定的菜單和父菜單會(huì )用另外定義的樣式來(lái)顯示。
一般的做法是在mouseover和mouseout中設置樣式,
但這里不行,因為有延時(shí),當鼠標快速移動(dòng)到另一個(gè)菜單,再移到原來(lái)的菜單上時(shí),
樣式就不會(huì )自動(dòng)設回來(lái),所以只好每次mouseover都重新設置每個(gè)容器的菜單的樣式。
暫時(shí)還找不到更好的方法,有的話(huà)記得通知我哦o(_ _)o

【擴展功能】
有這些屬性可以設置:
Position: 默認位置(up,down,left,right);
Tag: 默認生成標簽;
Class: 默認樣式;
onClass: 焦點(diǎn)樣式;
Delay: 延遲值(微秒);
暫時(shí)有這兩個(gè)方法:
Add(menu):添加菜單,參數是一個(gè)菜單結構;
Delete(index):刪除菜單,參數是菜單索引;
也可以直接修改_menu屬性,怎么擴展就看各位的想象力了。
程序測試:參數1是一個(gè)容器集合:
參數2是一個(gè)菜單結構:

參數3是一些設置:
實(shí)例化對象:
程序代碼:

下載完整實(shí)例

