(转)基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据
http://www.cnblogs.com/wuhuacong/p/3669708.html
最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采用EasyUI的前端界面处理技术,走MVC的技术路线,在重构完善过程中,很多细节花费不少时间进行研究和提炼,一步步走过来,也积累了不少经验,本系列将主要介绍我在进一步完善我的Web框架基础上积累的经验进行分享,本随笔主要介绍使用如何使用Json实体类构建菜单数据,然后在主界面中进行使用。
菜单的界面效果如下所示,菜单分为一级菜单、二级菜单、三级菜单,他们各自在位置上是不同的定义,这个界面布局规定三级菜单就是最小的菜单节点了,也就是叶子节点。

要实现以上的菜单,需要把菜单定义成相关的Json数据,然后通过脚本把它们添加到界面里面去,如下数据和脚本就是定义相关的菜单数据的。

<script type="text/javascript">
var _menus = {
"default": [
{
"menuid": "1", "icon": "icon-computer", "menuname": "权限管理",
"menus": [
{ "menuid": "13", "menuname": "用户管理", "icon": "icon-user", "url": "/User/Index" },
{ "menuid": "14", "menuname": "组织机构管理", "icon": "icon-organ", "url": "/OU/Index" },
{ "menuid": "15", "menuname": "角色管理", "icon": "icon-group-key", "url": "/Role/Index" },
{ "menuid": "16", "menuname": "功能管理", "icon": "icon-key", "url": "/Function/Index" },
{ "menuid": "17", "menuname": "登陆日志", "icon": "icon-view", "url": "/LoginLog/Index" }
]
},
{
"menuid": "2", "icon": "icon-user", "menuname": "其他管理",
"menus": [{ "menuid": "21", "menuname": "修改密码", "icon": "icon-lock", "url": "javascript:ShowPasswordDialog()" }
]
}
],
"point": [
{
"menuid": "3", "icon": "icon-computer", "menuname": "事务中心",
"menus": [
{ "menuid": "33", "menuname": "测试菜单1", "icon": "icon-user", "url": "../Commonpage/building.htm" },
{ "menuid": "34", "menuname": "测试菜单2", "icon": "icon-organ", "url": "../Commonpage/building.htm" },
{ "menuid": "35", "menuname": "测试菜单3", "icon": "icon-group-key", "url": "../Commonpage/building.htm" },
{ "menuid": "36", "menuname": "测试菜单4", "icon": "icon-key", "url": "../Commonpage/building.htm" }
]
},
{
"menuid": "4", "icon": "icon-user", "menuname": "其他菜单",
"menus": [{ "menuid": "41", "menuname": "测试菜单5", "icon": "icon-lock", "url": "../Commonpage/building.htm" }]
}
]
}; function showSubMenu(url, title, menuCategory, defaultIcon) {
if (defaultIcon == null || defaultIcon == "") {
defaultIcon = "icon-table";
}
addTab(title, url, "icon " + defaultIcon);
Clearnav();
if (menuCategory != "") {
addNav(_menus[menuCategory]);
}
}
</script>

从上面的菜单Json数据来看,它是一个字典的Json数据列表,在Web界面上,通过下面的代码可以展开上面Json定义的二级菜单。
<li><a href="#" onclick="showSubMenu('/User/Index', '用户管理', 'default')">权限管理</a></li>

虽然上面的定义的数据能够解决菜单的显示问题,但是对于我们需要动态控制的菜单,显然做不到,因此需要把上面的json数据,通过菜单控制器进行动态生成才可以,然后在脚本里面通过Jquery的方式获取Json数据,如下所示。

var _menus = {};
//同步获取
$.ajax({
type: 'GET',
url: '/Menu/GetMenuData?r=' + Math.random(),
async: false,//同步
dataType: 'json',
success: function (json) {
_menus = json;
},
error: function (xhr, status, error) {
alert("操作失败"); //xhr.responseText
}
});

上面的GetMenuData方法,通过后台的控制器进行动态生成的,它的代码如下所示

/// <summary>
/// 获取树形展示数据
/// </summary>
/// <returns></returns>
public ActionResult GetMenuData()
{
string json = GetTreeJson("-1", "", "");
json = json.Trim(',');
return Content(string.Format("[{0}]", json));
} /// <summary>
/// 递归获取树形信息
/// </summary>
/// <returns></returns>
private string GetTreeJson(string PID, string folderIcon, string leafIcon)
{
string condition = string.Format("PID='{0}' ", PID);
List<MenuInfo> nodeList = BLLFactory<Menu>.Instance.Find(condition);
StringBuilder content = new StringBuilder();
foreach (MenuInfo model in nodeList)
{
string ParentID = (model.PID == "-1" ? "0" : model.PID);
string subMenu = this.GetTreeJson(model.ID, folderIcon, leafIcon);
string parentMenu = string.Format("{{ \"id\":\"{0}\", \"pId\":\"{1}\", \"name\":\"{2}\" ", model.ID, ParentID, model.Name);
if (string.IsNullOrEmpty(subMenu))
{
if (!string.IsNullOrEmpty(leafIcon))
{
parentMenu += string.Format(",\"icon\":\"{0}\" }},", leafIcon);
}
else
{
parentMenu += "},";
}
}
else
{
if (!string.IsNullOrEmpty(folderIcon))
{
parentMenu += string.Format(",\"icon\":\"{0}\" }},", folderIcon);
}
else
{
parentMenu += "},";
}
} content.AppendLine(parentMenu.Trim());
content.AppendLine(subMenu.Trim());
}
return content.ToString().Trim();
}

不过对于上面的代码,我觉得虽然能解决问题,能够正确生成相关的Json代码,但是感觉不够优雅,我不喜欢使用拼凑方法构建数据。
前面看了Menu的Json脚本,我说过他是一个字典类型的Json数据格式,那么我们是否可以通过字典和实体信息来承载,然后直接通过ToJson方法出来呢?答案是可以的。

/// <summary>
/// 获取菜单的树形展示数据
/// </summary>
/// <returns></returns>
public ActionResult GetMenuData()
{
Dictionary<string, List<MenuData>> dict = new Dictionary<string, List<MenuData>>(); List<MenuInfo> list = BLLFactory<Menu>.Instance.GetTopMenu(MyConstants.SystemType);
int i = 0;
foreach (MenuInfo info in list)
{
if (!HasFunction(info.FunctionId))
{
continue;
}
List<MenuData> treeList = new List<MenuData>();
List<MenuNodeInfo> nodeList = BLLFactory<Menu>.Instance.GetTreeByID(info.ID);
foreach (MenuNodeInfo nodeInfo in nodeList)
{
if (!HasFunction(nodeInfo.FunctionId))
{
continue;
}
MenuData menuData = new MenuData(nodeInfo.ID, nodeInfo.Name, string.IsNullOrEmpty(nodeInfo.WebIcon) ? "icon-computer" : nodeInfo.WebIcon);
foreach (MenuNodeInfo subNodeInfo in nodeInfo.Children)
{
if (!HasFunction(subNodeInfo.FunctionId))
{
continue;
}
string icon = string.IsNullOrEmpty(subNodeInfo.WebIcon) ? "icon-organ" : subNodeInfo.WebIcon;
menuData.menus.Add(new MenuData(subNodeInfo.ID, subNodeInfo.Name, icon, subNodeInfo.Url));
}
treeList.Add(menuData);
} //添加到字典里面,如果是第一个,默认用default名称
string dictName = (i++ == 0) ? "default" : info.ID;
dict.Add(dictName, treeList);
} string content = ToJson(dict);
return Content(content.Trim(','));
}

上面的代码,通过MenuData的对象数据,来承载相关的菜单信息,然后把它添加到字典Dictionary<string, List<MenuData>> dict 里面就可以了,这样的代码,没有那么多拼凑出来的感觉,是不是很好看呢?把对象转换为Json数据,直接通过ToJson就可以解决了,很简单吧。
而菜单的权限控制,就是通过集合权限管理进行判断,父菜单如果没有权限,就直接跳过,不在继续生成下面的子菜单,权限判断的如下所示。
if (!HasFunction(info.FunctionId))
{
continue;
}
当然,在界面上展开二级菜单的操作界面,也应该通过脚本动态进行生成的,这样才能做到所有的内容动态构建。
<ul class="navigation" style="display:block">
@Html.Raw(@ViewBag.HeaderScript)</ul>
上面使用ViewBag对象进行传递脚本内容到界面上,其实后台生成的操作,是一行HTML代码就是了,代码类似下面的内容。
<li><a href="#" onclick="showSubMenu('/User/Index', '用户管理', 'default')">权限管理</a></li>
最后出来的效果,就是博客开始介绍的界面截图,没有任何变化,但是代码我们已经经过了几步的优化整理,看起来很清爽,更能实现动态变化了。

(转)基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据的更多相关文章
- 基于MVC4+EasyUI的Web开发框架经验总结
http://www.cnblogs.com/wuhuacong/p/4093778.html 在很多Web系统中,一般都可能提供一些图标的选择,方便配置按钮,菜单等界面元素的图 标,从而是Web系统 ...
- 基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作
在很多Web系统中,一般都可能提供一些图标的选择,方便配置按钮,菜单等界面元素的图标,从而是Web系统界面看起来更加美观和协调.但是在系统中一般内置的图标样式相对比较有限,而且硬编码写到样式表里面,这 ...
- 基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度
在默认情况下,EasyUI的DataGrid好像都没有具备自动宽度的适应功能,一般是指定像素宽度的,但是使用的人员计算机的屏幕分辨率可能不一样,因此导致有些地方显示太大或者太小,总是不能达到好的预期效 ...
- 基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式
在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交,方便页面和服务器后端进行数据的交互处理.本文主要介绍利用Jquery处理数据交互的几种方式,包括 ...
- 基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码
在Web开发的时候,我们很多时候,需要引用很多CSS文件.JS文件,随着使用更多的插件或者独立样式文件,可能我们的Web界面代码会越来越臃肿,看起来也很累赘,在MVC里面提供了一个Bundle的对象, ...
- 基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出
数据的导入导出,在很多系统里面都比较常见,这个导入导出的操作,在Winform里面比较容易实现,我曾经在之前的一篇文章<Winform开发框架之通用数据导入导出操作>介绍了在Winform ...
- 基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作
我们在使用EasyUI的时候,很多情况下需要使用到表格控件datagrid,这个控件控件非常强大,使用起来很简洁,但是我在使用中,发现对于一个表里面的外键字段进行转义,并显示引用表的一些名称的操作,却 ...
- 基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览
在博客园很多文章里面,曾经有一些介绍Office文档预览查看操作的,有些通过转为PDF进行查看,有些通过把它转换为Flash进行查看,但是过程都是曲线救国,真正能够简洁方便的实现Office文档的预览 ...
- 基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动
为了提高客户体验和进行一些技术探索,现在正准备把我自己的客户关系管理系统CRM在做一个Web的版本,因此对基于MVC的Web界面继续进行一些研究和优化,力求在功能和界面上保持和Winform一致,本文 ...
- 基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理
在很多Web界面中,我们都可以看到很多下拉列表的元素,有些是固定的,有些是动态的:有些是字典内容,有些是其他表里面的名称字段:有时候引用的是外键ID,有时候引用的是名称文本内容:正确快速使用下拉列表的 ...
随机推荐
- [luogu1129 ZJOI2007] 矩阵游戏 (二分图最大匹配)
传送门 Description Input Output Sample Input 2 2 0 0 0 1 3 0 0 1 0 1 0 1 0 0 Sample Output No Yes HINT ...
- Codeforces 851B/C
B. Arpa and an exam about geometry 传送门:http://codeforces.com/contest/851/problem/B 本题是一个平面几何问题. 平面上有 ...
- Bootstrap关于表单(一)
1.基础表单 表单中常见的元素主要包括:文本输入框.下拉选择框.单选按钮.复选按钮.文本域和按钮等. 在Bootstrap框架中,通过定制了一个类名`form-control`,也就是说,如果这几个元 ...
- QT中tableview不能更新数据,why?
model->select(); //model->removeColumn(0);++++++++++++++++++++ //model->setHeaderData(model ...
- 洛谷 P1595 信封问题
题目描述 某人写了n封信和n个信封,如果所有的信都装错了信封.求所有信都装错信封共有多少种不同情况. 输入输出格式 输入格式: 一个信封数n 输出格式: 一个整数,代表有多少种情况. 输入输出样例 输 ...
- 【日常学习】【搜索/递归】codevs2802 二的幂次方题解
转载请注明出处 [ametake版权全部]http://blog.csdn.net/ametake欢迎来看 题目描写叙述 Description 不论什么一个正整数都能够用2的幂次方表示. 比如:13 ...
- 解决MyEclipse开启后总是不停的在Update index
近期MyEclipse开启之后总是不停的在 update index,非常是耗时间. 查找资料发现Update index...是Maven在不断更新, 解决的方法例如以下: Window --> ...
- 利用JAVA反射机制设计通用的DAO
利用JAVA反射机制设计一个通用的DAO 反射机制 反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息. 反射机制创建类对象 ...
- Java程序猿的JavaScript学习笔记(9—— jQuery工具方法)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
- js自定义回调函数
JavaScript允许开发人员像传递任何类型的数据一样传递函数,也就是说,函数也是一种数据类型,通过typeof就知道. 例子1: var CallbackFun = function(){ t ...