不再为无限级树结构烦恼,且看此篇
很久都没有写点什么出来分享了,最近在做多级树的时候,发现来来回回写过很多遍,于是封装成用户控件,以方便日后重复使用.
首先上效果:
我们看到以上2种效果,都是支持任意级的,这里源码中使用的是递归,以便高效的完成HTML的渲染.
下面上代码,代码中解释的都很详细了,我就不再细说.下面将有示例调用演示:
public partial class UC_MultiLevelTree : System.Web.UI.UserControl { #region 数据相关属性 /// <summary> /// 要绑定的数据源 /// </summary> public DataTable DataSource { get; set; } /// <summary> /// 多级树显示文本所在列列名 /// </summary> public string TextFeild { get; set; } /// <summary> /// 多级树单条数据识别列列名(即选择项的值) /// </summary> public string ValueFeild { get; set; } /// <summary> /// 多级树层级区别列列名(仅限单个列区分层级) /// </summary> public string LevelFeild { get; set; } /// <summary> /// 多级树顶级的父项值 /// </summary> public string TopLevelFeildValue { get; set; } #endregion #region 显示相关属性 /// <summary> /// 是否显示多选框,默认为显示 /// </summary> public bool ShowCheckBox { get; set; } /// <summary> /// 是否显示自定义根节点 /// </summary> public bool ShowCustomerRoot { get; set; } /// <summary> /// 自定义根节点文本 /// </summary> public string CustomerRootText { get; set; } /// <summary> /// 多级树宽度,可为像素或者百分比 /// </summary> public string Width { get; set; } /// <summary> /// 多级树高度,可为像素或者百分比 /// </summary> public string Height { get; set; } /// <summary> /// 展开符号(可为HTML代码) /// </summary> public string ExtendSign { get; set; } /// <summary> /// 收缩符号(可为HTML代码) /// </summary> public string ShrinkSign { get; set; } /// <summary> /// 每级与上级空格个数 /// </summary> public int LevelSeparatorCount { get; set; } /// <summary> /// 默认展开级别 /// </summary> public int ExtendLevelNum { get; set; } #endregion #region 私有变量 /// <summary> /// 扩展标记的HTML /// </summary> private string StrExtendSign; /// <summary> /// 收缩标记的HTML /// </summary> private string StrShrinkSign; /// <summary> /// 多选框的HTML /// </summary> private string StrCheckbox; /// <summary> /// 子层级开始符号的HTML /// </summary> private string LevelSeparator = " "; #endregion protected override void OnInit(EventArgs e) { base.OnInit(e); this.ShowCheckBox = true; this.Width = "100%"; this.Height = "100%"; this.ExtendSign = "[+]"; this.ShrinkSign = "[-]"; this.TopLevelFeildValue = CRMCommon.strNullGuid; this.LevelSeparatorCount = 4; this.ExtendLevelNum = 2; } protected void Page_Load(object sender, EventArgs e) { } public void DataBind() { this.StrCheckbox = this.ShowCheckBox ? "<input type='checkbox' class='MLT_Checkbox'/>" : ""; this.StrExtendSign = "<span class='MLT_ExtendSign' {0}>" + this.ExtendSign + "</span>"; this.StrShrinkSign = "<span class='MLT_ShrinkSign' {0}>" + this.ShrinkSign + "</span>"; this.ltMultiLevelTreeHtml.Text = RenderTree(this.TopLevelFeildValue, 1); } private string RenderTree(string parentValue, int level) { StringBuilder sb = new StringBuilder(); string extendSignHtml = ""; string shrinkSignHtml = ""; //收缩,展开按钮的显示控制 if (level < this.ExtendLevelNum) { extendSignHtml = string.Format(this.StrExtendSign, "style='display:none;'"); shrinkSignHtml = string.Format(this.StrShrinkSign, ""); } else { extendSignHtml = string.Format(this.StrExtendSign, ""); shrinkSignHtml = string.Format(this.StrShrinkSign, "style='display:none;'"); } //自定义根节点 if (level == 1) { sb.AppendFormat("<div class='MLT_Panel' style='width:{0};height:{1}'>", this.Width, this.Height); if (this.ShowCustomerRoot) { sb.AppendFormat("<div class='MLT_Item' level='{0}' rel=''>{1}<span class='MLT_Item_Text'>{2}</span></div>", level, extendSignHtml + shrinkSignHtml + this.StrCheckbox, this.CustomerRootText); level += 1; } sb.Append(RenderTree(parentValue, level)); sb.Append("</div>"); } else if (level != 1) { //数据项绑定 if (this.DataSource != null && this.DataSource.Rows.Count > 0) { string levelSeparator = ""; if (level > 1) { levelSeparator += "<span class='MLT_LevelSeparator'>"; for (int i = 1; i <= (level - 1) * this.LevelSeparatorCount; i++) { levelSeparator += this.LevelSeparator; } levelSeparator += "</span>"; } DataRow[] drList = this.DataSource.Select(string.Format("{0}='{1}'", this.LevelFeild, parentValue)); if (drList != null && drList.Length > 0) { level += 1; foreach (DataRow dr in drList) { string childHtml = RenderTree(dr[ValueFeild].ToString(), level); string signs = string.IsNullOrWhiteSpace(childHtml) ? "<span class='MLT_ExtendSignPlaceholder'></span>" : extendSignHtml + shrinkSignHtml; sb.AppendFormat("<div class='MLT_Item' level='{0}' rel='{1}' parent='{2}' {3}>{4}<span class='MLT_Item_Text'>{5}</span></div>", level - 1, dr[ValueFeild], dr[LevelFeild], level - 1 > this.ExtendLevelNum ? "style='display:none;'" : "", levelSeparator + signs + this.StrCheckbox, dr[TextFeild]); if (!string.IsNullOrWhiteSpace(childHtml)) { sb.Append(childHtml); } } } } } return sb.ToString(); } }
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="UC_MultiLevelTree.ascx.cs" Inherits="UC_MultiLevelTree" %> <asp:Literal runat="server" ID="ltMultiLevelTreeHtml"></asp:Literal> <script> $(function () { $(".MLT_Item").click(function (e) { e.stopPropagation(); $(".MLT_Item").removeClass("MLT_Item_hover"); $(this).addClass("MLT_Item_hover"); extendItem(this); }); $(".MLT_ExtendSign").click(function (e) { e.stopPropagation(); var event = e.currentTarget; var item = $(event).parent(); extendItem(item); }) $(".MLT_ShrinkSign").click(function (e) { e.stopPropagation(); var event = e.currentTarget; var item = $(event).parent(); shrinkItem(item); }) $(".MLT_Checkbox").click(function (e) { e.stopPropagation(); var event = e.currentTarget; var item = $(event).parent(); var checked = $(event).attr("checked"); checkItems(item, checked); }); }); //展开项 function extendItem(obj) { var rel = $(obj).attr("rel"); if (rel != undefined && rel.length > 0) { $(obj).siblings("div[parent=" + rel + "]").each(function () { $(this).show(); }); } else { $(obj).siblings("div[level=2]").show(); } $(obj).find(".MLT_ExtendSign").hide(); $(obj).find(".MLT_ShrinkSign").show(); } //收缩项 function shrinkItem(obj) { var rel = $(obj).attr("rel"); if (rel != undefined && rel.length > 0) { $(obj).siblings("div[parent=" + rel + "]").each(function () { $(this).hide(); $(this).find(".MLT_ExtendSign").show(); $(this).find(".MLT_ShrinkSign").hide(); shrinkItem(this); }); } else { $(obj).siblings("div[level!=1]").hide(); $(obj).siblings("div[level!=1]").find(".MLT_ExtendSign").show(); $(obj).siblings("div[level!=1]").find(".MLT_ShrinkSign").hide(); } $(obj).find(".MLT_ExtendSign").show(); $(obj).find(".MLT_ShrinkSign").hide(); } //选择项 function checkItems(obj, checked) { var rel = $(obj).attr("rel"); if (rel != undefined && rel.length > 0) { if (checked) { $(obj).siblings("div[parent=" + rel + "]").each(function () { $(this).find("input[type=checkbox]").attr("checked", "checked"); checkItems(this, checked); }); } else { $(obj).siblings("div[parent=" + rel + "]").each(function () { $(this).find("input[type=checkbox]").removeAttr("checked"); checkItems(this, checked); }); } } else { if (checked) { $(obj).parent().find("input[type=checkbox]").attr("checked", "checked"); } else { $(obj).parent().find("input[type=checkbox]").removeAttr("checked"); } } } </script> <style type="text/css"> .MLT_Panel { white-space: nowrap; overflow: auto; } .MLT_Item { font-size: 12px; line-height: 20px; cursor: pointer; } .MLT_Item_hover { background-color: rgb(167, 205, 240); } .MLT_Item span { line-height: 20px; display: inline-block; } .MLT_Checkbox { position: relative; width: 12px; height: 12px; margin: 0 2px; bottom: 2px; } .MLT_ExtendSign, .MLT_ShrinkSign, .MLT_ExtendSignPlaceholder { font-family: "宋体"; width: 18px; text-align: center; } </style>
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="UC_MultiLevelTree.ascx.cs" Inherits="UC_MultiLevelTree" %> <asp:Literal runat="server" ID="ltMultiLevelTreeHtml"></asp:Literal> <script> $(function () { $(".MLT_Item").click(function (e) { e.stopPropagation(); $(".MLT_Item").removeClass("MLT_Item_hover"); $(this).addClass("MLT_Item_hover"); extendItem(this); }); $(".MLT_ExtendSign").click(function (e) { e.stopPropagation(); var event = e.currentTarget; var item = $(event).parent(); extendItem(item); }) $(".MLT_ShrinkSign").click(function (e) { e.stopPropagation(); var event = e.currentTarget; var item = $(event).parent(); shrinkItem(item); }) $(".MLT_Checkbox").click(function (e) { e.stopPropagation(); var event = e.currentTarget; var item = $(event).parent(); var checked = $(event).attr("checked"); checkItems(item, checked); }); }); //展开项 function extendItem(obj) { var rel = $(obj).attr("rel"); if (rel != undefined && rel.length > 0) { $(obj).siblings("div[parent=" + rel + "]").each(function () { $(this).show(); }); } else { $(obj).siblings("div[level=2]").show(); } $(obj).find(".MLT_ExtendSign").hide(); $(obj).find(".MLT_ShrinkSign").show(); } //收缩项 function shrinkItem(obj) { var rel = $(obj).attr("rel"); if (rel != undefined && rel.length > 0) { $(obj).siblings("div[parent=" + rel + "]").each(function () { $(this).hide(); $(this).find(".MLT_ExtendSign").show(); $(this).find(".MLT_ShrinkSign").hide(); shrinkItem(this); }); } else { $(obj).siblings("div[level!=1]").hide(); $(obj).siblings("div[level!=1]").find(".MLT_ExtendSign").show(); $(obj).siblings("div[level!=1]").find(".MLT_ShrinkSign").hide(); } $(obj).find(".MLT_ExtendSign").show(); $(obj).find(".MLT_ShrinkSign").hide(); } //选择项 function checkItems(obj, checked) { var rel = $(obj).attr("rel"); if (rel != undefined && rel.length > 0) { if (checked) { $(obj).siblings("div[parent=" + rel + "]").each(function () { $(this).find("input[type=checkbox]").attr("checked", "checked"); checkItems(this, checked); }); } else { $(obj).siblings("div[parent=" + rel + "]").each(function () { $(this).find("input[type=checkbox]").removeAttr("checked"); checkItems(this, checked); }); } } else { if (checked) { $(obj).parent().find("input[type=checkbox]").attr("checked", "checked"); } else { $(obj).parent().find("input[type=checkbox]").removeAttr("checked"); } } } </script> <style type="text/css"> .MLT_Panel { white-space: nowrap; overflow: auto; } .MLT_Item { font-size: 12px; line-height: 20px; cursor: pointer; } .MLT_Item_hover { background-color: rgb(167, 205, 240); } .MLT_Item span { line-height: 20px; display: inline-block; } .MLT_Checkbox { position: relative; width: 12px; height: 12px; margin: 0 2px; bottom: 2px; } .MLT_ExtendSign, .MLT_ShrinkSign, .MLT_ExtendSignPlaceholder { font-family: "宋体"; width: 18px; text-align: center; } </style>
示例:
使用原数据:
生成HTML中,每一级每一条都包含在使用相同class的DIV当中,不同之外在于自定义的level,parent,rel等属性,请参见代码.
下列为调用代码方法,各参数可自行设定,说见用户控件CS代码:
由于时间问题,可能很多地方不便细说.如有更多疑问,请加QQ群:ASP.NET高级群,群号: 261882616