最近花了不少时间在重构和进一步提炼我的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" ? "" : 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 = ;
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++ == ) ? "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开发框架的系列文章:

基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍

基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用

基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用

基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍

基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

基于MVC4+EasyUI的Web开发框架形成之旅--权限控制

基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录

基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据

基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts

基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder

基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动

基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览

基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码

基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作

基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据的更多相关文章

  1. 基于MVC4+EasyUI的Web开发框架经验总结

    http://www.cnblogs.com/wuhuacong/p/4093778.html 在很多Web系统中,一般都可能提供一些图标的选择,方便配置按钮,菜单等界面元素的图 标,从而是Web系统 ...

  2. 基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作

    在很多Web系统中,一般都可能提供一些图标的选择,方便配置按钮,菜单等界面元素的图标,从而是Web系统界面看起来更加美观和协调.但是在系统中一般内置的图标样式相对比较有限,而且硬编码写到样式表里面,这 ...

  3. 基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

    在默认情况下,EasyUI的DataGrid好像都没有具备自动宽度的适应功能,一般是指定像素宽度的,但是使用的人员计算机的屏幕分辨率可能不一样,因此导致有些地方显示太大或者太小,总是不能达到好的预期效 ...

  4. 基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

    在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交,方便页面和服务器后端进行数据的交互处理.本文主要介绍利用Jquery处理数据交互的几种方式,包括 ...

  5. 基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码

    在Web开发的时候,我们很多时候,需要引用很多CSS文件.JS文件,随着使用更多的插件或者独立样式文件,可能我们的Web界面代码会越来越臃肿,看起来也很累赘,在MVC里面提供了一个Bundle的对象, ...

  6. 基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

    数据的导入导出,在很多系统里面都比较常见,这个导入导出的操作,在Winform里面比较容易实现,我曾经在之前的一篇文章<Winform开发框架之通用数据导入导出操作>介绍了在Winform ...

  7. 基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

    我们在使用EasyUI的时候,很多情况下需要使用到表格控件datagrid,这个控件控件非常强大,使用起来很简洁,但是我在使用中,发现对于一个表里面的外键字段进行转义,并显示引用表的一些名称的操作,却 ...

  8. 基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览

    在博客园很多文章里面,曾经有一些介绍Office文档预览查看操作的,有些通过转为PDF进行查看,有些通过把它转换为Flash进行查看,但是过程都是曲线救国,真正能够简洁方便的实现Office文档的预览 ...

  9. 基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动

    为了提高客户体验和进行一些技术探索,现在正准备把我自己的客户关系管理系统CRM在做一个Web的版本,因此对基于MVC的Web界面继续进行一些研究和优化,力求在功能和界面上保持和Winform一致,本文 ...

  10. 基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

    在很多Web界面中,我们都可以看到很多下拉列表的元素,有些是固定的,有些是动态的:有些是字典内容,有些是其他表里面的名称字段:有时候引用的是外键ID,有时候引用的是名称文本内容:正确快速使用下拉列表的 ...

随机推荐

  1. Unity3D热更新全书-脚本(二) 两级分化

    上篇明确了我们探讨的脚本是什么:是写在文本文件里面的代码,可以作为资源加载,取得字符串再执行. 可是为什么世界上会有那么多的脚本?而其使用方法完全看起来不一样呢?这是因为每种脚本都有自己的定位,在不同 ...

  2. [php入门] 2、基础核心语法大纲

    1 前言 最近在学PHP,上节主要总结了PHP开发环境搭建<[php入门] 1.从安装开发环境环境到(庄B)做个炫酷的登陆应用>.本节主要总结PHP的核心基础语法,基本以粗轮廓写,可以算作 ...

  3. java指定路径写、读文件

    package com.util; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; ...

  4. Flex contextMenu

    没想到再这里也要跌跌撞撞. 这个东西我很久之前就懂了的啊! 最开始是这么写的: private function init():void { var contextMenu:ContextMenu = ...

  5. salesforce 零基础学习(二十一)workflow Q&A

    有一篇内容专门写了workflow,后来用到的时候心生疑问,不知道小伙伴有没有和我想法一样的,workflow具体内容原来已经说过,不在过多叙述,只说一下运行条件. 那就是:当满足运行条件时,执行相关 ...

  6. 学习bootstrap遇到的问题--001 关于bootstrap中类.disabled不禁用默认行为

    自学bootstrap遇到的疑惑篇: 按钮状态--禁用 在Bootstrap框架中,要禁用按钮有两种实现方式: 方法1:在标签中添加disabled属性 方法2:在元素标签中添加类名"dis ...

  7. 初了解JS设计模式,学习笔记

    什么是设计模式. 回答这个问题,往往我们得先知道我们为什么需要设计模式,正是因为有需求才会有设计模式,难道不是吗? 我们为什么需要设计模式. 如果没有按照设计模式去写,你的代码很可能是乱无肆忌写的,也 ...

  8. C# 集合类 :(Array、 Arraylist、List、Hashtable、Dictionary、Stack、Queue)

    我们用的比较多的非泛型集合类主要有 ArrayList类 和 HashTable类.我们经常用HashTable 来存储将要写入到数据库或者返回的信息,在这之间要不断的进行类型的转化,增加了系统装箱和 ...

  9. IO流-ZIP文档

    java中通常使用ZipInputStream来读ZIP文档 ZIP文档(通常)以压缩格式存储了一个或多个文件,每个ZIP文档都有一个包含诸如文件 名字和所使用的压缩方法等信息的头.在Java中,可以 ...

  10. SOLID原则

    SOLID是面向对象设计和编程(OOD&OOP)中几个重要编码原则 即:SRP单一责任原则: OCP开放封闭原则: LSP里氏替换原则: ISP接口分离原则: DIP依赖倒置原则. 1. 单一 ...