實現覆選框樹的多層級表單控制項,類似於多層級的角色與許可權控制功能,支持CheckBox,允許對菜單項進行選擇,方便的與MVC結合,能夠以提交表單的方式,一次性將樹綁定到後臺接收的對象 ...
類似於多層級的角色與許可權控制功能,用MVC實現MVC樹控制項,mvc中應用treeview,實現覆選框樹的多層級表單控制項。最近我們的項目中需要用到樹型菜單,以前使用WebForm時,樹型菜單有微軟提供的控制項,非常方便,但現在需要在asp.netmvc中使用樹形菜單,先說明下我們對樹形菜單的需求:
1,支持CheckBox,允許對菜單項進行選擇;
2,當選擇父菜單時,它下麵的子菜單全部選中;
3,當取消父菜單的選中狀態時,下麵的子菜單也全部取消;
4,比較方便的與MVC結合;
5,能夠初始化選中狀態。
6,能夠以提交表單的方式,一次性將樹綁定到後臺接收的對象。
首先菜單數據對象:
完整的 CheckboxTreeHelper.cs 代碼:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using System.Web.Mvc.Html; 7 using System.Text; 8 9 /* 10 author:熊學浩 11 time:2016年6月5日 12 description:樹形菜單控制項(有問題請致信:[email protected]),或者請參考【http://www.cnblogs.com/xiongzaiqiren/】 13 */ 14 namespace System.Web.Mvc 15 { 16 /// <summary> 17 /// 菜單數據對象 18 /// </summary> 19 public class CheckboxTreeItem 20 { 21 /// <summary> 22 /// 顯示的文本 23 /// </summary> 24 public string Text { get; set; } 25 /// <summary> 26 /// 顯示文本對應的值 27 /// </summary> 28 public string Value { get; set; } 29 /// <summary> 30 /// 是否被選中 31 /// </summary> 32 public bool Checked { get; set; } 33 /// <summary> 34 /// 結合表單的輔助屬性,View上使用(註意每個層級的索引必需從0開始並且是連續的) 35 /// </summary> 36 public string Index { get; set; } 37 38 /// <summary> 39 /// 子菜單集合 40 /// </summary> 41 public IList<CheckboxTreeItem> Items { get; set; } 42 } 43 44 /// <summary> 45 /// 覆選框樹控制項 46 /// 熊學浩 47 /// 2016年6月3日 48 /// </summary> 49 public static class CheckboxTreeHelper 50 { 51 private static bool baselayer; 52 53 public static String CheckboxTree(this HtmlHelper helper, string Name, CheckboxTreeItem Model, out string this_HtmlDomName, bool isChildNode = false) 54 { 55 if (null == Model) 56 { 57 this_HtmlDomName = string.Empty; 58 return string.Empty; 59 } 60 61 StringBuilder sb = new StringBuilder(); 62 if (!baselayer) 63 sb.Append("<div class=\"CheckboxTree\">"); 64 65 if (!isChildNode) 66 sb.Append("<ul class=\"CBT-ul\">"); 67 sb.Append("<li class=\"CBT-li\">"); 68 69 this_HtmlDomName = Name + "[" + Model.Index + "]"; 70 71 sb.Append("<label style=\"cursor:pointer;\">"); 72 sb.AppendFormat("<input type=\"checkbox\" onchange=\"setCheckboxTreeItemValue(this);\" name=\"{0}\" value=\"{1}\" />", (this_HtmlDomName + ".Checked"), Model.Checked.ToString()); 73 sb.AppendFormat("<span>{0}</span>", Model.Text); 74 sb.Append("</label>"); 75 76 sb.AppendFormat("<input type=\"hidden\" name =\"{0}\" value=\"{1}\" />", (this_HtmlDomName + ".Text"), Model.Text); 77 sb.AppendFormat("<input type=\"hidden\" name =\"{0}\" value=\"{1}\" />", (this_HtmlDomName + ".Value"), Model.Value); 78 sb.AppendFormat("<input type=\"hidden\" name =\"{0}\" value=\"{1}\" />", (this_HtmlDomName + ".Index"), Model.Index); 79 80 if (null != Model.Items) 81 { 82 sb.Append("<ul class=\"CBT-ul\">"); 83 for (var i = 0; i < Model.Items.Count; i++) 84 { 85 string _this_HtmlDomName; 86 sb.Append(CheckboxTree(helper, this_HtmlDomName + ".Items", Model.Items[i], out _this_HtmlDomName, true)); 87 } 88 sb.Append("</ul>"); 89 } 90 91 sb.Append("</li>"); 92 if (!isChildNode) 93 sb.Append("</ul>"); 94 95 if (!baselayer) 96 sb.Append("</div>"); 97 98 return sb.ToString(); 99 } 100 public static String CheckboxTree(this HtmlHelper helper, string Name, IList<CheckboxTreeItem> Models) 101 { 102 if (null == Models) return string.Empty; 103 if (Models.Count > 0) 104 baselayer = true; 105 106 StringBuilder sb = new StringBuilder(); 107 if (baselayer) 108 sb.Append("<div class=\"CheckboxTree\">"); 109 sb.Append("<ul class=\"CBT-ul\">"); 110 111 string _this_HtmlDomName; 112 113 foreach (CheckboxTreeItem item in Models) 114 { 115 sb.Append(CheckboxTree(helper, Name, item, out _this_HtmlDomName, true)); 116 } 117 118 sb.Append("</ul>"); 119 if (baselayer) 120 sb.Append("</div>"); 121 122 return sb.ToString(); 123 } 124 } 125 }
欄位說明:
Text:用於顯示的文本,比如:總裁
Value:顯示文本對應的ID,比如:0
Index:這個是結合表單的輔助屬性,View上使用(註意每個層級的索引必需從0開始並且是連續的)
Checked:當前菜單項是否被選中,用戶提交表單後我們可以通過這個屬性判斷用戶的選擇項
Items:當前菜單下的子菜單集合
樹形菜單的輸出:
1 @model List<CheckboxTreeItem> 2 3 4 @using (Html.BeginForm("test", "Home", new { }, FormMethod.Post, new { id = "form", name = "form" })) 5 { 6 @Html.AntiForgeryToken(); 7 8 <link type="text/css" rel="stylesheet" href="@Url.Content("~/Models/CheckboxTree.css")" /> 9 @Html.Raw(Html.CheckboxTree("CheckboxTree", Model)) @*這裡是輸出顯示樹形菜單*@ 10 <script src="@Url.Content("~/Models/CheckboxTree.js")" type="text/javascript"></script> 11 }
無論是ajax還是直接post表單,最終的目的都是接收View中的數據,要想傳遞比較複雜的數據類型,我們需要對ASP.NET MVC Model Binding 有一定瞭解,之前也講解過MyTreeViewItem的結果,有普通的數據類型,比如 string,bool,也是對象類型,比如MyTreeViewItem類型的Parent,也是基於集合的屬性IList<MyTreeViewItem>,要想讓表單中的數據直接傳遞給Controller,我們需要對錶單元素的name進行特殊處理才行。
Controller:這是最重要的就是接收參數,它是一個List類型,無論菜單項有多少層,都會按樹形數據結構層次組織好,方便我們查詢。
1 public ActionResult test(int id = 0) 2 { 3 ViewBag.IsEdit = id == 0 ? false : true; 4 5 List<CheckboxTreeItem> cb = new List<CheckboxTreeItem>() { 6 new CheckboxTreeItem() { Value="A", Text="一級A", Index="0" }, 7 new CheckboxTreeItem() { Value="B", Text="一級B", Index="1" }, 8 new CheckboxTreeItem() { Value="C", Text="一級C", Index="2", Checked =true, 9 Items=new List<CheckboxTreeItem>() { 10 new CheckboxTreeItem() { Value="CA", Text="二級CA", Index="0", Checked =true }, 11 new CheckboxTreeItem() { Value="CB", Text="二級CB", Index="1", Checked =true, 12 Items=new List<CheckboxTreeItem>() { 13 new CheckboxTreeItem() { Value="CBA", Text="三級CBA", Index="0", Checked =true }, 14 new CheckboxTreeItem() { Value="CBB", Text="三級CBB", Index="1", Checked =true }, 15 } 16 }, 17 } 18 }, 19 }; 20 21 return View(cb); 22 } 23 24 [HttpPost] 25 [ValidateAntiForgeryToken] 26 [ValidateInput(false)] 27 public ActionResult test(List<CheckboxTreeItem> CheckboxTree, int id = 0) 28 { 29 ViewBag.IsEdit = id == 0 ? false : true; 30 31 return View(CheckboxTree); 32 }
下圖是Controller接收到的參數:(運行調試,斷點查看第27-31行代碼)
另外還有自定義樣式文件 CheckboxTree.css
1 /* 2 author:熊學浩 3 time:2016年6月5日 4 description:樹形菜單控制項(有問題請致信:[email protected]),或者請參考【http://www.cnblogs.com/xiongzaiqiren/】 5 */ 6 /* CheckboxTree */ 7 .CheckboxTree { 8 width: 100%; 9 height: 100%; 10 text-align: center; 11 margin: 0 auto; 12 } 13 14 .CBT-ul { 15 text-align: left; 16 list-style-type: disc; 17 } 18 19 .CBT-ul .CBT-li { 20 display: list-item; 21 text-align: left; 22 margin-left: 10px; 23 font-size: 16px; 24 line-height: 20px; 25 word-wrap: break-word; 26 word-break: nomal; 27 list-style: inherit; 28 } 29 .CBT-li label { 30 cursor: pointer; 31 } 32 .CBT-li label input[type="checkbox"] { 33 width: 16px; 34 height: 16px; 35 padding: 0 5px 0 0; 36 } 37 38 .CBT-li span { 39 40 } 41 42 .CBT-li a:link, .CBT-li a:visited { 43 } 44 45 .CBT-li a:hover, .CBT-li a:active { 46 color: #ffffff; 47 background-color: #657386; 48 } 49 50 .CBT-li a.active { 51 color: #ffffff; 52 background-color: #657386; 53 } 54 55 .CBT-li a span { 56 57 }CheckboxTree.css
用於初始化和設置選擇狀態改變的自定義javascript文件 CheckboxTree.js
1 /* 2 author:熊學浩 3 time:2016年6月5日 4 description:樹形菜單控制項(有問題請致信:[email protected]),或者請參考【http://www.cnblogs.com/xiongzaiqiren/】 5 */ 6 /* CheckboxTree */ 7 function setCheckboxTreeItemValue(dom) { 8 try { 9 if (!!dom) 10 dom.value = (!!dom.checked) 11 } 12 catch (e) { 13 console.log(e.message); 14 } 15 }; 16 function iniCheckboxTree() { 17 try { 18 var cbList = document.getElementsByTagName("input"); 19 if (!!cbList && cbList.length > 0) { 20 for (var i = 0; i < cbList.length; i++) { 21 if (!!cbList[i] && (cbList[i].type == "checkbox")) { 22 if (!!cbList[i].value) { 23 cbList[i].checked = (cbList[i].value.toLowerCase() == "true") || false; 24 } 25 } 26 } 27 } 28 } 29 catch (e) { 30 console.log(e.message); 31 } 32 }; 33 34 if (!!window) 35 window.onload = iniCheckboxTree(); 36 else 37 iniCheckboxTree();CheckboxTree.js
最後,UI效果圖:
【完】