打造html右鍵菜單

今天是給你們介紹一款在網頁上使用的右鍵菜單,原做者的網址是:http://51jsr.javaeye.com/blog/305517javascript

這個右鍵菜單已經很是優秀,不過呢。倒是IE Only,並且在DTD模式下
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd%22>css

連IE顯示都是有問題的,因此呢只有本身動手了,另外就順便改形成jQuery控件,順便分析一下代碼。html

首先來看一下效果吧java

image

↑這是控件的效果數組

image ←Windows Se7en 系統的郵件菜單app

插一句吧,其實我最終的目標是提供一個ASP.NET MVC 框架前臺UI Controls解決方案,由於後面的控件會用到這個右鍵菜單因此就講一下。框架

首先仍是來分析一下HTML吧dom

1:一級菜單(每一組菜單)便是一個獨立的div容器ide

2:每一項又是div,嵌套一個nobr(可用div代替不過要額外寫個class)的標籤,裏面是圖標和span包裹的位置內容函數

image菜單項/菜單組    image 分割線

這裏一個要注意的地方就是多級菜單其實在HTMl結構是分離的,只是經過顯示的位置在視覺上給人連載一塊兒(另外就是箭頭圖標了)

第二接着是CSS了(是修改過的)

CSS很是簡單,由於HTML結構自己也不復雜

CSS中會用到的全部圖片 m_arrow m_item m_splitLine menu_bg  注意有四張圖片哦。。

第三來看javascript了

先來看個完整的吧

那接着就一步一步來分析唄,首先既然改形成jQuery控件那麼天然仍是老架子

1
2
3
4
;( function ($) {
     $.fn.contextmenu = function (option) {
     }
})(jQuery);
接着是默認參數了哦
1
2
3
//alias:"惟一標示"(這個標示很重要哦,能夠實現屢次調用只生成一個菜單哦),
//width菜單寬度
option = $.extend({ alias: "cmroot" , width: 150 }, option);
默認參數只有兩個,另外幾個的只是沒有默認值而已
1
2
3
4
5
6
/*參數說明
option: {width:Number, items:Array, onShow:Function, rule:JSON}
成員語法(三種形式)    -- para.items
-> {text:String, icon:String, type:String, alias:String, width:Number, items:Array}        --    菜單組
-> {text:String, icon:String, type:String, alias:String, action:Function }                --    菜單項
-> {type:String}   --分割線*/

詳細描述下:

items:Array 右鍵菜單的內容定義,數組的元素格式以下所示:

{text: String, icon: String, alias: String, type: "group"|"item"|"splitLine", width:int, items:Array,action:Funtion}

其中:
text:String 菜單項的文字說明 。
icon: String 圖標的Src地址,若是沒有圖標,若是item不須要圖標,請設置成none.gif(在images/icons/中能夠找到)。
alias:String 惟一標識菜單項。
type:"group"|"item"|"splitLine" 分別爲組,項,分割線,當選擇是"splitLine"則其餘設置項無需設置。
width:int 當且僅當type="group"時有效,設置新組容器的寬度。

items:Array 子元素可無限層次。
action:Function 當菜單項被點擊時被使用
alias: String (可選參數)惟一標識,當頁面上只有一種右鍵菜單時能夠省略
width : Number (可選參數) 右鍵菜單根的寬度, 默認值:150px。
onContextMenu: Function (可選參數) 當右鍵菜單觸發時預先調用的函數,返回參數爲Boolean指示是否顯示菜單
onShow: Function (可選參數) 當菜單顯示時觸發,通常在該函數中應用規則
rule : Json (可選參數) 默認規則,設置哪些項默認爲禁用,格式以下所示 { name:String, disable: Boolean, items:Array}

name:String 規則名稱 disable:Boolean 規則是禁用仍是啓用 items:Array 須要應用規則的item alias的集合

有點複雜哈,若是還有不明白看示例哈。

定義一堆臨時變量,還有4個模板臨時變量

1
2
3
4
5
6
7
    var ruleName = null , target = null ,
        groups = {}, mitems = {}, actions = {}, showGroups = [], //定義內部的臨時變量。用到的地方再來分析
    //一個菜單項的模板哦  ,容器和項,分割線的模板
itemTpl = "<div class='b-m-$[type]' unselectable=on><nobr unselectable=on><img src='$[icon]' align='absmiddle'/><span unselectable=on>$[text]</span></nobr></div>" ;
        var gTemplet = $( "<div/>" ).addClass( "b-m-mpanel" ).attr( "unselectable" , "on" ).css( "display" , "none" );
        var iTemplet = $( "<div/>" ).addClass( "b-m-item" ).attr( "unselectable" , "on" );
        var sTemplet = $( "<div/>" ).addClass( "b-m-split" );

接着咱們要跳過一些函數的定義,直接來看建立HTML的部分

 

1
2
3
4
5
6
7
8
9
10
11
12
//獲取菜單的跟
var $root = $( "#" + option.alias);
       var root = null ;
       if ($root.length == 0) { //若是頂級不存在,這建立頂級菜單哦
           root = buildGroup.apply(gTemplet.clone()[0], [option]);
           root.applyrule = applyRule; //把一個方法註冊到dom上
           root.showMenu = showMenu; //另一個方法註冊的該dom上
           addItems(option.alias, option.items); //添加菜單項
       }
       else {
           root = $root[0]; //不然就用這個了
       }
這個代碼很玄乎,好像作了些什麼好像有什麼都沒作,其實只有來看下buildGroup方法和addItems才知道到底幹了什麼
1
2
3
4
5
6
7
8
9
10
11
12
13
var buildGroup = function (obj) { //建立菜單容器
         groups[obj.alias] = this ; //菜單項註冊到臨時變量中
         this .gidx = obj.alias;
         this .id = obj.alias;
         if (obj.disable) { //若是是禁用狀態
             this .disable = obj.disable;
             this .className = "b-m-idisable" ;
         }
     //設置菜單寬度,設置事件的阻止事件冒泡,並添加到body中
         $( this ).width(obj.width).click(returnfalse).mousedown(returnfalse).appendTo($( "body" ));
         obj = null ;
         return this ; //返回菜單自己
     };

有了容器就能夠往裏面添加菜單項了,我在代碼中加了詳細的註釋了,應該能夠很好的理解了

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
//添加菜單項
   var addItems = function (gidx, items) {
       var tmp = null ;
       for ( var i = 0; i < items.length; i++) {
           if (items[i].type == "splitLine" ) { //若是是分割線
               //菜單分隔線
               tmp = sTemplet.clone()[0];
           } else {
               items[i].gidx = gidx; //把group的標識賦給item上
               if (items[i].type == "group" ) {
                   //菜單組
                   buildGroup.apply(gTemplet.clone()[0], [items[i]]); //每一個菜單組都是獨立的div哦,因此頂級同樣調用生產組的方法
                   arguments.callee(items[i].alias, items[i].items); //遞歸生成菜單項
                   items[i].type = "arrow" ; //若是是group生成箭頭
                   tmp = buildItem.apply(iTemplet.clone()[0], [items[i]]); //生成菜單項的html
               } else {
                   //菜單項
                   items[i].type = "ibody" ;
                   tmp = buildItem.apply(iTemplet.clone()[0], [items[i]]); //生成菜單項的html
                   $(tmp).click( function (e) { //若是菜單項那麼註冊click事件
                       if (! this .disable) {
                           if ($.isFunction(actions[ this .idx])) {
                               actions[ this .idx].call( this , target);
                           }
                           hideMenuPane();
                       }
                       return false ;
                   });
 
               } //Endif
            //把菜單項的右鍵事件屏蔽,同時註冊hover的效果
               $(tmp).bind( "contextmenu" , returnfalse).hover(overItem, outItem);
           } //Endif
           groups[gidx].appendChild(tmp); //把菜單項添加到group的中
           tmp = items[i] = items[i].items = null ;
       } //Endfor
       gidx = items = null ;
   };

builditem方法就比較簡單,就不詳細描述了,接着咱們仍是繼續往下看主流程了哦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var me = $( this ).each( function () {
        //給元素添加右鍵事件了哦
             return $( this ).bind( 'contextmenu' , function (e) {
         //若是(option.onContextMenu 存在則調用並判斷返回值是否顯示菜單,能夠利用這個在特定狀況下禁用菜單
                 var bShowContext = (option.onContextMenu && $.isFunction(option.onContextMenu)) ? option.onContextMenu.call( this , e) : true ;
                 if (bShowContext) {
             //觸發onShow事件,這個事件中能夠執行修改rule,禁用某幾項菜單項哦
                     if (option.onShow && $.isFunction(option.onShow)) {
                         option.onShow.call( this , root);
                     }
                     root.showMenu(e, this ); //調用顯示菜單
                 }
         //阻止冒泡
                 return false ;
             });
         });
         //設置顯示規則,第一次執行時的規則,同時也能夠onshow中動態設置rule
         if (option.rule) {
             applyRule(option.rule);
         }

基本就OK了,另外幾個方法就比較簡單了,還有亮點是邊緣的處理,這個前面的datepicker中也有相應的說明邏輯差很少就不在描述了,一樣仍是來看下demo吧。關於打包下載,你們能夠把demo的網頁完整的另存爲便可

http://jscs.cloudapp.net/ControlsSample/CM

你的支持是我繼續寫做的動力。

歡迎轉載,可是請保留原連接:http://www.cnblogs.com/xuanye/archive/2009/10/29/1592585.html

相關文章
相關標籤/搜索