類似的多級浮動菜單網(wǎng)上也很多實例,但大部分都是只針對一種情況或不夠靈活,簡單說就是做死了的。
所以我就想到做一個能夠自定義菜單的,有更多功能的多級浮動菜單。
而其中的關(guān)鍵就是怎么根據(jù)自定義的菜單結(jié)構(gòu)來生成新菜單,
關(guān)鍵中的難點就是怎么得到下級菜單結(jié)構(gòu)和容器對象的使用。
理想的做法是每次有下級菜單時,從對象直接取得下級菜單結(jié)構(gòu),放到容器對象中,
并且容器能重用,而不是每次都重新生成。
但想了很久也想不到適合的做法,直到做了多級聯(lián)動下拉菜單終于得到了靈感。
放棄了直接取得下級菜單結(jié)構(gòu),而是每次都從原來的菜單結(jié)構(gòu)中獲取當前需要的下級菜單結(jié)構(gòu)。
容器對象也不是自動生成,而是由用戶先定義好(后來也做到能自動生成了)。
放下了這些包袱后,后面的開發(fā)就順暢了。
特點:
1.根據(jù)自定義菜單結(jié)構(gòu)生成菜單;
2.多級聯(lián)動功能;
3.自定義浮動位置(上下左右);
4.自定義延遲效果;
5.js控制編輯菜單;
6.可根據(jù)需要自動生產(chǎn)容器對象;
效果:
程序原理(建議參照代碼閱讀):
程序是根據(jù)傳統(tǒng)浮動菜單擴展而來,這里說一下幾個比較關(guān)鍵或有用的地方:
【延時功能】這個很多人都懂,就是設(shè)個setTimeout計時器,這里有兩個計時器,分別是容器計時器和菜單計時器。
容器計時器的作用是鼠標移到容器外面時隱藏容器,難點是如何判斷當前鼠標是不是在容器外面。
一般的方法是設(shè)個bool參數(shù),mouseout時設(shè)為false,mouseover時設(shè)為true(or倒過來),再根據(jù)這個參數(shù)判斷,
但這個方法在這個不行,經(jīng)過容器里的菜單對象時會觸發(fā)容器mouseout,
由于事件冒泡,菜單對象的mouseout也會觸發(fā)容器的mouseout。
例如:
這里推薦一個方法,使用contains(ff是compareDocumentPosition)方法。
這個方法是我做圖片滑動展示效果時muxrwc教我的:
Each(oThis.Container, function(o, i){ if(o.contains ? o.contains(oT) || o == oT : o.compareDocumentPosition(oT) & 16){ isIn = true; } });
詳細參考仿LightBox內(nèi)容顯示效果,而菜單計時器就沒什么特別,就是用來設(shè)置菜單內(nèi)容。
【浮動位置】除了母菜單的容器是固定的,子菜單的容器都是絕對定位的,定位的關(guān)鍵就是取得適合的left和top值。
首先要取得上一級菜單的left和top值。
由于母菜單是相對定位的,要取它的絕對left和top值就必須逐層向上取值,并加起來:
取得上一級菜單的left和top值后,再進行相應(yīng)的移位就可以了:
這里要注意,如果display為none的話會取不到offset值,
所以為了在隱藏的狀態(tài)也能定位,就要用visibility來隱藏。
當然如果display可以先顯示再定位,但這樣會出現(xiàn)瞬間移動的現(xiàn)象,不建議。
【自動生成容器對象】
除了第一個容器對象,當發(fā)現(xiàn)容器不夠時,會根據(jù)前一個容器來生成新容器。
開始時我想用cloneNode,但由于對象中有事件所以不能這樣用,只能手動建一個。
為了使用相同的樣式,復(fù)制cssText(這個也是muxrwc告訴我的)和className到新容器,
然后用IniContainer()函數(shù)設(shè)置一下就可以了:
【多級聯(lián)動】
多級聯(lián)動的關(guān)鍵是如何得到子菜單結(jié)構(gòu)和根據(jù)這個子菜單結(jié)構(gòu)生成菜單對象。
先說說菜單結(jié)構(gòu),是類似這樣的結(jié)構(gòu):
知道json的應(yīng)該都知道是什么了,js的一種對象結(jié)構(gòu):
txt是顯示的內(nèi)容,也可以是html,到時會innerHTML插入;
position是位置,可以是"right"(默認),"down","up","left",浮動位置會根據(jù)這個值來設(shè)置;
menu是下一級的菜單結(jié)構(gòu)。
可以看出這類似一個n維數(shù)組,注意是類似。
那怎么根據(jù)這個菜單結(jié)構(gòu)獲得當前菜單的子菜單呢?
首先從菜單對象的onmouseover說起,
在菜單a的onmouseover中,要做的是重新設(shè)置菜單和重新設(shè)置樣式(這個稍后再說)。
設(shè)置菜單還包括設(shè)置一個索引屬性index來記錄當前容器菜單的索引(容器第幾個菜單),
這里有點取巧的是容器菜單的索引跟對應(yīng)菜單結(jié)構(gòu)中menu的索引是相同的(后面會用到),
而_index是當前容器的索引(第幾個容器),同樣這里的索引也可以用來指示當前菜單在第幾級。
還要設(shè)置_onmenu為當前的菜單對象,它在取浮動位置時需要用到。
然后就可以用Set()程序來設(shè)置菜單了:
在Set()程序中第一部是先隱藏select,這是通用的做法了:
設(shè)置一個參數(shù),作為容器集合的索引,這里可以直接從第二級開始,所以設(shè)i初始值為1。
用一個while來反復(fù)取子菜單結(jié)構(gòu)(menu),直到?jīng)]有子菜單(menu長度為0)或者取得了子菜單結(jié)構(gòu)(_index==i)。
這里沒有用for,因為我覺得while比較合適,或者for更好也說不定。
這里除了取得子菜單結(jié)構(gòu)也要取得子菜單的定位(position)。
期間如果容器不夠會自動添加。
取得了子菜單結(jié)構(gòu)和定位后,就可以用SetContainer()設(shè)置下一級菜單容器了:
程序SetContainer()用的技巧不多,首先對容器進行相關(guān)設(shè)置,在使用了SetMenu()來設(shè)置菜單對象,
然后是容器的定位和顯示,最后隱藏不需要的容器,這部分就不說明了。
要說說的是SetMenu()程序,它的作用是根據(jù)菜單結(jié)構(gòu)設(shè)置菜單對象并放到容器中。
根據(jù)菜單結(jié)構(gòu)的每個元素創(chuàng)建一個菜單對象,innerHTML元素的txt屬性,設(shè)置mouseover事件,最后appendChild到容器中。
這里比較重要的是mouseover事件,在mouseover事件中會重新設(shè)置菜單和重新設(shè)置樣式,
當觸發(fā)mouseover事件就回到一開頭的“從菜單對象的onmouseover說起”(輪回!-_-)。
不知你暈不暈,反正剛開始時我是比較暈的了。
【焦點樣式設(shè)置】
這里說的就是SetMenu()中重新設(shè)置樣式的部分。
程序中可以看出鼠標指定的菜單和父菜單會用另外定義的樣式來顯示。
一般的做法是在mouseover和mouseout中設(shè)置樣式,
但這里不行,因為有延時,當鼠標快速移動到另一個菜單,再移到原來的菜單上時,
樣式就不會自動設(shè)回來,所以只好每次mouseover都重新設(shè)置每個容器的菜單的樣式。
暫時還找不到更好的方法,有的話記得通知我哦o(_ _)o
【擴展功能】
有這些屬性可以設(shè)置:
Position: 默認位置(up,down,left,right);
Tag: 默認生成標簽;
Class: 默認樣式;
onClass: 焦點樣式;
Delay: 延遲值(微秒);
暫時有這兩個方法:
Add(menu):添加菜單,參數(shù)是一個菜單結(jié)構(gòu);
Delete(index):刪除菜單,參數(shù)是菜單索引;
也可以直接修改_menu屬性,怎么擴展就看各位的想象力了。
程序測試:參數(shù)1是一個容器集合:
參數(shù)2是一個菜單結(jié)構(gòu):
參數(shù)3是一些設(shè)置:
實例化對象:
程序代碼:
下載完整實例





