效果预览:
由于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的引用路径都是用全路径的方式引用。