MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件

类似于多层级的角色与权限控制功能,用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="@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 else
37     iniCheckboxTree();
CheckboxTree.js

最后,UI效果图:

【完】

 

posted @ 2016-06-05 18:35  熊仔其人  阅读(3796)  评论(3编辑  收藏  举报