效果预览:
由于jquery的树形菜单需要使用特定格式的json数据,才能显示出来如上图的效果,因此需要我们在后台处理并拼接json字符串。笔者通过构造一棵树的数据类型,然后将节点信息保存到树中的各个节点实现的,过程如下所示:
public class Tree<T> { public Tree() { nodes = new List<Tree<T>>(); } public Tree(T data) { this.Data = data; nodes = new List<Tree<T>>(); } private Tree<T> parent; /// <summary> /// 父结点 /// </summary> public Tree<T> Parent { get { return parent; } } /// <summary> /// 结点数据 /// </summary> public T Data { get; set; } /// <summary> /// URL /// </summary> public string URL { get; set; } /// <summary> /// 目录是否展开 /// </summary> public bool Open { get; set; } private List<Tree<T>> nodes; /// <summary> /// 子结点 /// </summary> public List<Tree<T>> Nodes { get { return nodes; } } /// <summary> /// 添加结点 /// </summary> /// <param name="node">结点</param> public void AddNode(Tree<T> node) { if (!nodes.Contains(node)) { node.parent = this; nodes.Add(node); } } /// <summary> /// 添加结点 /// </summary> /// <param name="nodes">结点集合</param> public void AddNode(List<Tree<T>> nodes) { foreach (var node in nodes) { if (!nodes.Contains(node)) { node.parent = this; nodes.Add(node); } } } /// <summary> /// 移除结点 /// </summary> /// <param name="node"></param> public void Remove(Tree<T> node) { if (nodes.Contains(node)) nodes.Remove(node); } /// <summary> /// 清空结点集合 /// </summary> public void RemoveAll() { nodes.Clear(); } /// <summary> /// 将树转换为Json字符串 /// </summary> /// <param name="root"></param> /// <returns></returns> public static string ToJson(Tree<T> root) { string result = ""; result += "{\"id\":" + 1; result += ",\"text\":\"" + root.Data; result += "\""; result += ",\"state\":\"" + root.Open; result += "\""; result += ",\"attributes\":{\"url\":\"" + root.URL; result += "\"}"; if (root.Nodes.Count > 0) { result += ",\"children\":"; result += "["; foreach (var item in root.Nodes) { result += ToJson(item); result += ","; } result = result.Remove(result.Length - 1, 1); result += "]"; } result += "}"; return result; } /// <summary> /// 查看下一层中是否存在某一个节点 /// </summary> /// <param name="root"></param> /// <param name="search"></param> /// <returns></returns> public static bool Exists(Tree<string> root, string search) { if (root.Nodes.Count > 0) { foreach (var item in root.Nodes) { if (item.Data.Equals(search)) { return true; } } } return false; } /// <summary> /// 查找下一层中是否包含某一个节点,若包含,则返回该节点 /// </summary> /// <param name="root"></param> /// <param name="search"></param> /// <returns></returns> public static Tree<string> FindNode(Tree<string> root, string search) { if (root.Nodes.Count > 0) { foreach (var item in root.Nodes) { if (item.Data.Equals(search)) { return item; } } } return null; } /// <summary> /// 查找节点 /// </summary> /// <param name="root"></param> /// <param name="menus"></param> /// <returns></returns> public static Tree<string> SetMenuUrl(Tree<string> root, Hashtable menus) { //设置当前节点url信息 if (menus.ContainsKey(root.Data)) { root.URL = menus[root.Data].ToString(); } if (root.Nodes.Count > 0) { //深度优先遍历(只要存在子节点,就遍历子节点) foreach (var item in root.Nodes) { SetMenuUrl(item, menus); } } return root; } }
后端定义了一个后台处理程序GetMenu.ashx,其处理函数如下所示:
public void ProcessRequest(HttpContext context) { string result = ""; string sql = ""; Tree<string> root = new Tree<string>(); DataTable dTable = null; Hashtable menus = WebUI.GetAllMenuUrl(); try { //在.ashx中引用 session 必须继承IReadOnlySessionState/IRequiresSessionState,否则无法获取Session对象 switch (context.Session["角色"].ToString()) { case "管理员": sql = "SELECT * FROM `web`.`menue`"; ////整理菜单 dTable = data.GetTable(sql); if (dTable.Rows.Count > 0) { root.Data = "总部"; for (int i = 0; i < dTable.Rows.Count; i++) { Tree<string> node1 = Tree<string>.FindNode(root, dTable.Rows[i]["集团名称"].ToString()); //不存在集团 if (node1 == null) { node1 = new Tree<string>(); node1.Data = dTable.Rows[i]["集团名称"].ToString(); root.AddNode(node1); } Tree<string> node2 = Tree<string>.FindNode(node1, dTable.Rows[i]["工厂名称"].ToString()); //不存在工厂 if (node2 == null) { node2 = new Tree<string>(); node2.Data = dTable.Rows[i]["工厂名称"].ToString(); node1.AddNode(node2); } Tree<string> node3 = Tree<string>.FindNode(node2, dTable.Rows[i]["机组名称"].ToString()); //不存在机组 if (dTable.Rows[i]["机组名称"].ToString() != "" && node3 == null) { node3 = new Tree<string>(); node3.Data = dTable.Rows[i]["机组名称"].ToString(); node2.AddNode(node3); } } } break; case "集团负责人": sql = "SELECT * FROM `web`.`menue` where 用户名='" + context.Session["用户名"].ToString() + "'"; ////整理菜单 dTable = data.GetTable(sql); if (dTable.Rows.Count > 0) { root.Data = dTable.Rows[0]["集团名称"].ToString(); for (int i = 0; i < dTable.Rows.Count; i++) { Tree<string> node1 = Tree<string>.FindNode(root, dTable.Rows[i]["工厂名称"].ToString()); //不存在工厂 if (node1 == null) { node1 = new Tree<string>(); node1.Data = dTable.Rows[i]["工厂名称"].ToString(); root.AddNode(node1); } Tree<string> node2 = Tree<string>.FindNode(root, dTable.Rows[i]["机组名称"].ToString()); //不存在机组 if (dTable.Rows[i]["机组名称"].ToString() != "" && node1 == null) { node2 = new Tree<string>(); node2.Data = dTable.Rows[i]["机组名称"].ToString(); node1.AddNode(node2); } } } break; case "工厂负责人": sql = "SELECT * FROM `web`.`menue` where 用户名='" + context.Session["用户名"].ToString() + "'"; ////整理菜单 dTable = data.GetTable(sql); if (dTable.Rows.Count > 0) { root.Data = dTable.Rows[0]["工厂名称"].ToString(); for (int i = 0; i < dTable.Rows.Count; i++) { Tree<string> node1 = Tree<string>.FindNode(root, dTable.Rows[i]["工厂名称"].ToString()); //不存在工厂 if (node1 == null) { node1 = new Tree<string>(); node1.Data = dTable.Rows[i]["机组名称"].ToString(); root.AddNode(node1); } Tree<string> node2 = Tree<string>.FindNode(root, dTable.Rows[i]["机组名称"].ToString()); //不存在机组 if (dTable.Rows[i]["机组名称"].ToString() != "" && node1 == null) { node2 = new Tree<string>(); node2.Data = dTable.Rows[i]["机组名称"].ToString(); node1.AddNode(node2); } } } break; case "机组人员": sql = "SELECT * FROM `web`.`menue` where 用户名='" + context.Session["用户名"].ToString() + "'"; ////整理菜单 dTable = data.GetTable(sql); if (dTable.Rows.Count > 0) { root.Data = dTable.Rows[0]["机组名称"].ToString(); for (int i = 0; i < dTable.Rows.Count; i++) { Tree<string> node1 = Tree<string>.FindNode(root, dTable.Rows[i]["机组名称"].ToString()); //不存在工厂 if (node1 == null) { node1 = new Tree<string>(); node1.Data = dTable.Rows[i]["机组名称"].ToString(); root.AddNode(node1); } } } break; case "专家": sql = ""; break; default: break; } //遍历树,设置URL和是否打开标志 Tree<string>.SetMenuUrl(root, menus); result = "[" + Tree<string>.ToJson(root) + "]"; } catch (Exception ex) { context.Response.ContentType = "text/plain"; context.Response.Write(ex.Message); } context.Response.ContentType = "text/plain"; context.Response.Write(result); }需要注意的是,笔者通过ToJson方法生成的Json字符串还需要在两边加上"["和"]"。
此时,前端需要做的就相对简单了:
1.添加树形菜单标签(注意先引入jquery和easyui)
<ul class="easyui-tree" id="treeMenu" data-options="url:'/GetMenu.ashx',method:'get',animate:true,lines:true"></ul>
2.定义菜单点击事件
<script type="text/javascript"> <%-- 树形菜单的点击事件 --%> $(function () { $("#treeMenu").tree({ onClick: function (node) { if (node.attributes !== undefined && node.attributes.url !== undefined) { //跳转到url指定的页面 window.location.href=node.attributes.url; } } }); }); </script>
注意:由于User下的Show.aspx页面和母版页Site.Master不在同一目录下,所以,在母版中的路径都需要使用全路径,防止出现路径的引用问题。
如下图所示,jQuery的引用路径都是用全路径的方式引用。