這段時間沒事,做了一個動態菜單的實現。有很多的地方想的不是很全,做的不夠完善。歡迎大神們拍磚和指點!
話不多說,進入正題:
設計了一個數據庫表:
在設計的時候每一個菜單的子菜單最多能添加 99 個,子菜單編號根據父菜單編號拼接上同級子菜單的個數。
這里因為要用到Easyui,一些子段是按照easyui屬性設計的。
EF使用的是數據庫優先方式創建。
貼上代碼:
1.HTML代碼:

1 <style type="text/css"> 2 header { 3 height:60px; 4 } 5 aside{ 6 float:left; 7 width:200px; 8 } 9 article{ 10 margin-left:204px 11 } 12 </style> 13 <body> 14 <header> 15 EasyUI treegrid 實現動態菜單 16 </header> 17 18 <aside> 19 @*樹形菜單*@ 20 <ul id="tt"></ul> 21 </aside> 22 <article> 23 24 @*treegrid數據表格*@ 25 26 <table id="treegrid" style="width: 600px; height: 400px"></table> 27 28 @*treegrid的右鍵菜單*@ 29 <div id="tree_menu" class="easyui-menu" style="width: 120px;"> 30 <div> 31 <span>數據操作</span> 32 <div style="width: 120px;"> 33 <div id="add" data-options="iconCls:'icon-add0'">添加節點</div> 34 <div id="edit" data-options="iconCls:'icon-edit0'">修改節點</div> 35 <div id="delete" data-options="iconCls:'icon-delete0'">刪除節點</div> 36 </div> 37 </div> 38 <div id="ref" data-options="iconCls:'icon-new0'">刷 新</div> 39 <div class="menu-sep"></div> 40 <div>Exit</div> 41 </div> 42 @*添加,修改表單(彈窗模式)*@ 43 <div class ="treegrid_dialog" style="display: none;"> 44 <form id="treegrid_form"> 45 @*菜單主鍵*@ 46 <input type="hidden" name ="MId" /> 47 @*父菜單編號*@ 48 <input type="hidden" name ="pid" id="menuPid" /> 49 @*菜單編號*@ 50 <input type="hidden" name ="id" /> 51 <table> 52 <tr> 53 <td>菜單名稱</td><td><input class="easyui-validatebox" name="text" data-options="required:true" /></td> 54 </tr> 55 <tr> 56 <td>菜單圖標</td><td><input id="icon" name="iconCls" editable="false"/></td> 57 </tr> 58 <tr> 59 <td>菜單路徑</td><td><input class="easyui-validatebox" name="url" data-options="required:true" /></td> 60 </tr> 61 <tr> 62 <td>菜單是否選中</td> 63 <td> 64 <input id="yes" type="radio" name="checked" value="1" /><label for="yes">是</label> 65 <input id="no" type="radio" name="checked" value="0" /><label for="no">否</label> 66 </td> 67 </tr> 68 </table> 69 </form> 70 </div> 71 </article> 72 </body>
2.JavaScript代碼:

1 var treegrid; 2 var treegrid_dialog; 3 var iconData; 4 $(function () { 5 //綁定菜單tree數據 6 $('#tt').tree({ 7 url: '/System/GetTree' 8 }); 9 10 iconData = [{ 11 value: '', 12 text: '默認' 13 }, { 14 value: 'icon-add', 15 text: 'icon-add' 16 }, { 17 value: 'icon-edit', 18 text: 'icon-edit' 19 }, { 20 value: 'icon-remove', 21 text: 'icon-remove' 22 }, { 23 value: 'icon-save', 24 text: 'icon-save' 25 }, { 26 value: 'icon-cut', 27 text: 'icon-cut' 28 }, { 29 value: 'icon-ok', 30 text: 'icon-ok' 31 }, { 32 value: 'icon-no', 33 text: 'icon-no' 34 }, { 35 value: 'icon-cancel', 36 text: 'icon-cancel' 37 }, { 38 value: 'icon-reload', 39 text: 'icon-reload' 40 }, { 41 value: 'icon-search', 42 text: 'icon-search' 43 }, { 44 value: 'icon-print', 45 text: 'icon-print' 46 }, { 47 value: 'icon-help', 48 text: 'icon-help' 49 }, { 50 value: 'icon-undo', 51 text: 'icon-undo' 52 }, { 53 value: 'icon-redo', 54 text: 'icon-redo' 55 }, { 56 value: 'icon-back', 57 text: 'icon-back' 58 }, { 59 value: 'icon-sum', 60 text: 'icon-sum' 61 }, { 62 value: 'icon-tip', 63 text: 'icon-tip' 64 }]; 65 66 treegrid= $('#treegrid').treegrid({ 67 url: '/System/GetTree', 68 idField: 'id', 69 treeField: 'text', 70 columns: [[ 71 { title: '菜單名稱', field: 'text', width: 180 }, 72 { 73 title: '菜單圖標', field: 'iconCls', width: 100, 74 formatter: function (value) { 75 if (value!=null) { 76 return '<span class="' + value+ '"></span>'; 77 } 78 } 79 }, 80 { title: '菜單路徑', field: 'url', width: 100 }, 81 { title: '是否選中', field: 'checked', width: 100 } 82 ]], 83 onContextMenu: function (e, row) { 84 e.preventDefault(); 85 $(this).treegrid('unselectAll'); 86 $(this).treegrid('select', row.id); 87 $('#tree_menu').menu('show', { 88 left: e.pageX, 89 top: e.pageY 90 }); 91 } 92 }); 93 //刷新treegrid數據 94 $("#ref").click(function () { 95 treegrid.treegrid('reload'); 96 }); 97 //添加節點 98 $("#add").click(function () { 99 //取得選中節點 100 var node = treegrid.treegrid('getSelected'); 101 //清空表單數據 102 $("#treegrid_form").form('clear'); 103 $("#no").attr("checked", "true");//添加節點--設置表單(菜單是否選中)--默認選擇‘否’ 104 $("#menuPid").val(node.id); //設置將要添加節點 的 父節點編號 105 $("#icon").combobox({ 106 //url: '../../Content/data/icondata.json', 107 //valueField: 'id', 108 //textField: 'text' 109 data: iconData 110 }); 111 treegrid_dialog = $(".treegrid_dialog").show().dialog({ 112 modal: true, 113 title: '添加 ' + node.text + ' 節點的子節點', 114 closed: false, 115 width: 400, 116 height: 250, 117 cache: false, 118 collapsible: true, 119 maximizable: true, 120 resizable: true, 121 buttons: [{ 122 text: '保 存', 123 plain:true, 124 iconCls: 'icon-save', 125 handler: function () { 126 //數據驗證 通過與否 127 var validate = $("#treegrid_form").form('validate'); 128 if (validate == false) { 129 return false; 130 } 131 132 $.ajax({ 133 url: '/System/AddMenu', 134 data: $("#treegrid_form").serialize(), 135 type: 'POST', 136 cache: false, 137 dataType: 'json', 138 success: function (data) { 139 if (data && data.Success) { 140 $.messager.show({ title: '提示', msg: '' + data.Msg + '', timeout: 5000, showType: 'slide' }); 141 treegrid_dialog.dialog('close'); 142 treegrid.treegrid('reload'); 143 } 144 else { 145 $.messager.show({ title: '提示', msg: '' + data.Msg + '', timeout: 5000, showType: 'slide' }); 146 treegrid_dialog.dialog('close'); 147 treegrid.treegrid('reload'); 148 } 149 } 150 }); 151 } 152 }, { 153 text: '取 消', 154 iconCls: 'icon-redo', 155 plain: true, 156 handler: function () { 157 treegrid_dialog.dialog('close'); 158 } 159 }] 160 }); 161 }); 162 //編輯節點 163 $("#edit").click(function () { 164 //取得選中節點 165 var node = treegrid.treegrid('getSelected'); 166 //清空表單數據 167 $("#treegrid_form").form('clear'); 168 treegrid_dialog = $(".treegrid_dialog").show().dialog({ 169 modal: true, 170 title: '編輯 ' + node.text + ' 節點', 171 closed: false, 172 width: 400, 173 height: 250, 174 cache: false, 175 collapsible: true, 176 maximizable: true, 177 resizable: true, 178 buttons: [{ 179 text: '保 存', 180 plain:true, 181 iconCls: 'icon-save', 182 handler: function () { 183 //數據驗證 通過與否 184 var validate = $("#treegrid_form").form('validate'); 185 if (validate == false) { 186 return false; 187 } 188 $.ajax({ 189 url: '/System/EditMenu', 190 data: $("#treegrid_form").serialize(), 191 type: 'POST', 192 cache: false, 193 dataType: 'json', 194 success: function (data) { 195 if (data && data.Success) { 196 $.messager.show({ title: '提示', msg: '' + data.Msg + '', timeout: 5000, showType: 'slide' }); 197 treegrid_dialog.dialog('close'); 198 treegrid.treegrid('reload'); 199 } 200 else { 201 $.messager.show({ title: '提示', msg: '' + data.Msg + '', timeout: 5000, showType: 'slide' }); 202 treegrid_dialog.dialog('close'); 203 treegrid.treegrid('reload'); 204 } 205 } 206 }); 207 } 208 }, { 209 text: '取 消', 210 iconCls: 'icon-redo', 211 plain: true, 212 handler: function () { 213 treegrid_dialog.dialog('close'); 214 } 215 }] 216 }); 217 //綁定編輯窗口表單數據 218 $("#treegrid_form").form('load', node); 219 }); 220 //刪除節點 221 $("#delete").click(function () { 222 //取得選中節點 223 var node = treegrid.treegrid('getSelected'); 224 $.post('/System/DeleteMenu', { MId: node.MId }, function (data) { 225 if (data && data.Success) { 226 $.messager.show({ title: '提示', msg: '' + data.Msg + '', timeout: 5000, showType: 'slide' }); 227 treegrid.treegrid('reload'); 228 } 229 else { 230 $.messager.show({ title: '提示', msg: '' + data.Msg + '', timeout: 5000, showType: 'slide' }); 231 treegrid.treegrid('reload'); 232 } 233 }); 234 }); 235 });
3.后台Controller方法

1 private SYS_UserLimitEntities db = new SYS_UserLimitEntities(); 2 3 public ActionResult Index() 4 { 5 return View(); 6 } 7 8 #region 取得樹形菜單 + ActionResult GetTree(string id) 9 /// <summary> 10 /// 取得樹形菜單 11 /// </summary> 12 /// <param name="id">用戶點擊tree時,向后台訪問父菜單編號</param> 13 /// <returns></returns> 14 [HttpPost] 15 public ActionResult GetTree(string id) 16 { 17 try 18 { 19 List<Menu> list = null; 20 //判斷是否執行點擊tree時,按需加載要擴展的菜單 21 if (id != null) 22 { 23 list = db.Menu.Where(a => a.pid == id).ToList(); 24 } 25 else 26 { 27 list = db.Menu.Where(a => a.pid == "000").ToList();//取得根菜單 28 } 29 return Json(list);//返回easyui展示數據的json數據 30 } 31 catch (Exception) 32 { 33 throw; 34 } 35 } 36 #endregion 37 38 #region 添加菜單操作 + ActionResult AddMenu(Menu menu) 39 /// <summary> 40 /// 添加菜單操作 41 /// </summary> 42 /// <param name="menu">收集到的Menu菜單各個屬性的值</param> 43 /// <returns></returns> 44 [HttpPost] 45 public ActionResult AddMenu(Menu menu) 46 { 47 Messages m = new Messages(); 48 try 49 { 50 string newid = null;//將要添加菜單的編號 51 //判斷將要添加子菜單的父菜單狀態是否為父菜單狀態/否則修改 52 Menu me = db.Menu.Single(a => a.id == menu.pid); 53 if (me.state == "open") 54 { 55 me.state = "closed"; 56 } 57 //取得將要添加子菜單同級菜單-----並倒序排列 58 var mlist = db.Menu.Where(a => a.pid == menu.pid).OrderByDescending(a => a.MId).ToList(); 59 //判斷與將要添加的子菜單的同級菜單數目是否為0 60 if (mlist.Count > 0) 61 { 62 //取得同級菜單編號最大的的最后 兩位 以便計算出將要添加菜單編號 63 string id = mlist[0].id; 64 int i = Convert.ToInt32(id.Substring(id.Length - 2, 2)) + 1; 65 //限定每一個子菜單的數目不得超過99個 66 if (i == 100) 67 { 68 m.Msg = "該菜單的子菜單已經達到最大數目了,你可以選擇創建其他菜單選項"; 69 return Json(m); 70 } 71 //判斷子菜單編號后兩位是否為‘01’兩位形式不是則補填為兩位 72 newid = i > 9 ? mlist[0].pid + i.ToString() : mlist[0].pid + "0" + i.ToString(); 73 } 74 else 75 { 76 newid = menu.pid + "01";//沒有同級菜單時候就默認添加菜單的編號為 父菜單編號+‘01’ 77 } 78 //修改將要添加菜單的菜單編號 79 menu.id = newid; 80 menu.state = "open"; 81 //寫入數據庫 82 db.Menu.Add(menu); 83 84 db.SaveChanges(); 85 m.Msg = "成功的添加["+menu.text+"]的菜單節點信息!"; 86 m.Success = true; 87 return Json(m); 88 } 89 catch (Exception ex) 90 { 91 m.Msg = "添加失敗!" + ex.Message; 92 return Json(m); 93 } 94 } 95 #endregion 96 97 #region 編輯菜單操作 + ActionResult EditMenu(Menu menu) 98 /// <summary> 99 /// 編輯菜單操作 100 /// </summary> 101 /// <param name="menu">收集表單Menu數據</param> 102 /// <returns></returns> 103 [HttpPost] 104 public ActionResult EditMenu(Menu menu) 105 { 106 Messages m = new Messages(); 107 try 108 { 109 //將要修改的菜單添加到EF容器 110 DbEntityEntry<Menu> entry = db.Entry<Menu>(menu); 111 //設置包裝類對象狀態為unchanged 112 entry.State = System.Data.EntityState.Unchanged; 113 //設置改變的屬性 114 entry.Property(a => a.text).IsModified = true; 115 entry.Property(a => a.url).IsModified = true; 116 entry.Property(a => a.@checked).IsModified = true; 117 entry.Property(a => a.iconCls).IsModified = true; 118 //提交數據庫 119 db.SaveChanges(); 120 m.Msg = "節點["+menu.text+"]的信息修改成功!"; 121 m.Success = true; 122 return Json(m); 123 } 124 catch (Exception ex) 125 { 126 m.Msg = "修改失敗!" + ex.Message; 127 return Json(m); 128 } 129 } 130 #endregion 131 132 #region 刪除菜單操作 + ActionResult DeleteMenu(int MId) 133 /// <summary> 134 /// 刪除菜單操作 135 /// </summary> 136 /// <param name="MId">將要刪除的菜單編號</param> 137 /// <returns></returns> 138 [HttpPost] 139 public ActionResult DeleteMenu(int MId) 140 { 141 Messages m = new Messages(); 142 try 143 { 144 //取得將要刪除的實體對象 145 Menu menu = db.Menu.Single(a => a.MId == MId); 146 // 刪除項有--子菜單時 147 /* 148 * 從選中的節點開始,將其節點以及其一下節點都刪除 149 * --無論從那個節點開始刪除都能自如的將其子菜單以及子子菜單刪除,以此類推 150 */ 151 List<Menu> mlist = db.Menu.Where(a => a.id.IndexOf(menu.id)>=0).ToList(); 152 if (mlist.Count>0) 153 { 154 foreach (var item in mlist) 155 { 156 db.Menu.Remove(item); 157 } 158 } 159 db.Menu.Remove(menu); 160 db.SaveChanges(); 161 m.Msg = "節點已經被成功刪除!"; 162 m.Success = true; 163 return Json(m); 164 } 165 catch (Exception ex) 166 { 167 m.Msg = "刪除失敗!" + ex.Message; 168 return Json(m); 169 } 170 } 171 #endregion
效果圖如下:
實例下載地址:
http://pan.baidu.com/share/link?shareid=512055&uk=2804979851
功能自己搗鼓,不足之處還望各位看客指出修正。