类似于多层级的角色与权限控制功能,用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:树形菜单控件(有问题请致信:xiongzaiqiren@163.com),或者请参考【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='/images/loading.gif' data-original="@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:树形菜单控件(有问题请致信:xiongzaiqiren@163.com),或者请参考【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:树形菜单控件(有问题请致信:xiongzaiqiren@163.com),或者请参考【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 else37 iniCheckboxTree();
CheckboxTree.js
最后,UI效果图:
【完】
原标题:MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件
关键词:ie