在做权限系统的时候,需要有一个树形的菜单。下图就是一个树形菜单的样式
但问题是,我们可以实现写死的树形菜单。什么是写死的?就是在前台代码中写好要加载的树形菜单是什么样子的。但是我们权限系统的要求是动态加载树形菜单,也就是根据数据库里面表的内容动态加载。
我首先要说的就是数据库设计,要想动态加载成树形菜单,数据库表中就一定要设置父节点ID和自身ID。通过父节点ID判断自身是属于哪一级菜单,而通过自身ID判断其对应的下一级菜单。这是数据库设计应该注意的地方,如果没有父节点和自身子节点,那么就没办法实现动态加载树形菜单。
动态加载树形菜单的实现利用的zTree。这里顺便提一下,zTree的网站做的真的很好,而且各种类型的zTree做的非常完美。我就是利用zTree来实现的,只不过与之不同的是zTree实现的树菜单也是在前台写好的,我们要做的就是将后台用数据库查询到的代码拼接成前台已经写好的代码格式。
这是前台写好的树菜单格式:
我们要做的就是将前台这种树形菜单格式在后台拼出来,而在树形菜单中显示的菜单名称是从数据库中查询出来的。最开始的时候尝试拼JSON串,但是事实证明,我失败了,拼出来的字符串运行的时候根本显示不出来
拼出的JSON串跟咱们要拼接的格式是不同的,JSON串拼接出来的格式适用于结构比较简单,这样利用循环可以将需要的字符串拼接出来。而我们需要的字符串是需要判断下一级是否有子节点的,这个利用JSON串我没有实现,只能实现一级菜单,而对应的实现三级菜单我没有拼出来。很遗憾,但是利用循环、遍历和DataTable的查询,最终实现了树形菜单字符串的拼接。下面是我实现的代码
这个对应的实现二级菜单的拼接
[csharp]view plaincopy
publicstringgetTree(stringstrTree)
{
stringChilstr="";
//获取DataTable
zTreeBLLzTree=newzTreeBLL();
DataTabledt=newDataTable();
dt=zTree.QueryResource();
//查询父节点有多少条不重复的数据
zTreeBLLzTree1=newzTreeBLL();
DataTabledt1=newDataTable();
dt1=zTree1.QueryParidNum();
//父节点只能加到4
//for(intp=0;p //{
intparentId=0;
//查找第一个父节点有多少个,即初值为0的父节点
DataRow[]rowsP=dt.Select("ParentID="+parentId);
//利用循环将父节点拼接起来
for(inti=0;i {
//把rowsP里面的数值取出来
foreach(DataRowdrPinrowsP)
{
stringparName=drP["ResourceName"].ToString();
//strTree="[{name:\""+parName+"\"";
strTree="[{name:\""+parName+"\"";
DataRow[]rowsC=dt.Select("ParentID="+parentId+1);
if(rowsC.Length>0)//如果子节点不为0,则开始拼接子节点的字符串
{
//利用循环将父节点对应下的子节点串起来
foreach(DataRowdrCinrowsC)
{
stringchilName=drC["ResourceName"].ToString();
Chilstr=Chilstr+"{name:\""+chilName+"\"}";
Chilstr=Chilstr+",";
}
Chilstr=Chilstr.Remove(Chilstr.LastIndexOf(","),1);
strTree=strTree+",children:["+Chilstr+"]}];";
}
else
{
strTree=strTree+"\"}];";
}
}
}
//parentId++;
//}
returnstrTree;
}
这个对应的是多级菜单的拼接
[csharp]view plaincopy
publicstringgetTree(stringstrTree)
{
stringChilstr="";
//获取DataTable
zTreeBLLzTree=newzTreeBLL();
DataTabledt=newDataTable();
dt=zTree.QueryResource();
//查询父节点有多少条不重复的数据
zTreeBLLzTree1=newzTreeBLL();
DataTabledt1=newDataTable();
dt1=zTree1.QueryParidNum();
//父节点只能加到4
//for(intp=0;p //{
intparentId=0;
//查找第一个父节点有多少个,即初值为0的父节点
DataRow[]rowsP=dt.Select("ParentID="+parentId);
//利用循环将父节点拼接起来
for(inti=0;i {
//把rowsP里面的数值取出来
foreach(DataRowdrPinrowsP)
{
stringparName=drP["ResourceName"].ToString();
//strTree="[{name:\""+parName+"\"";
strTree="[{name:\""+parName+"\"";
DataRow[]rowsC=dt.Select("ParentID="+parentId+1);
if(rowsC.Length>0)//如果子节点不为0,则开始拼接子节点的字符串
{
//利用循环将父节点对应下的子节点串起来
foreach(DataRowdrCinrowsC)
{
stringThreestr="";
//判断二级菜单下对应的ID,也就是查找三级菜单的ParentID
stringchilFollow=drC["ID"].ToString();
//查询三级菜单
DataRow[]rowsThree=dt.Select("ParentID="+chilFollow);
//判断是否存在三级菜单
if(rowsThree.Length>0)
{
foreach(DataRowdrThreeinrowsThree)
{
stringThreeName=drThree["ResourceName"].ToString();
Threestr=Threestr+"{name:\""+ThreeName+"\"}";
Threestr=Threestr+",";
}
Threestr=Threestr.Remove(Threestr.LastIndexOf(","),1);
stringchilName=drC["ResourceName"].ToString();
Chilstr=Chilstr+"{name:\""+chilName+"\",children:["+Threestr+"]},";
}
//如果不存在三级菜单的话直接加载二级菜单
else
{
stringchilName=drC["ResourceName"].ToString();
Chilstr=Chilstr+"{name:\""+chilName+"\"}";
Chilstr=Chilstr+",";
}
}
Chilstr=Chilstr.Remove(Chilstr.LastIndexOf(","),1);
strTree=strTree+",children:["+Chilstr+"]}];";
}
else
{
strTree=strTree+"\"}];";
}
}
}
returnstrTree;
}
最终实现的效果
其实实现这个例子的方法还有很多种,比如说递归。虽然JSON串没有拼接成功,但是我觉得JSON串是可以实现的。只是鉴于个人能力的缘故最终没有拼接成功。动态加载树形菜单终于实现的,但是还有很多需要改进的地方,比如如何将这个方法封装起来,以至于可以无限的调用没有缺陷等,这是下一步值得继续探讨的问题。