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

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

基于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实体类构建菜单数据,如需转载请自行联系原博主。

时间: 2024-10-30 03:59:01

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

基于MVC4+EasyUI的Web开发框架经验总结(17)--布局和对话框自动适应大小的处理

在我自己的<Web开发框架>中,用了很多年的EasyUI,最新版本EasyUI为1.4.5,随着版本的更新,其很多功能得到了很大的完善和提高,同时也扩展了一些新的功能,以前在布局和对话框弹出层的自动适应大小的问题,也在最近的一些版本得到了解决,本文在迁移到最新EasyUI版本的时候,总结了一些经验,希望对大家使用这个强大的Web界面组件有所帮助. 1.Web主界面的布局调整 上面的布局是顶部内容+一级菜单.左边菜单,右边主内容为页面内容,页面内容是变化的内容,其他部分为不变的,这样的布局代码如

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

在默认情况下,EasyUI的DataGrid好像都没有具备自动宽度的适应功能,一般是指定像素宽度的,但是使用的人员计算机的屏幕分辨率可能不一样,因此导致有些地方显示太大或者太小,总是不能达到好的预期效果,如果DataGrid能够根据窗口尺寸进行伸缩,效果应该好很多.本文主要介绍DataGrid控件实现自动适应宽带高度的操作. 首先我们需要定义一个resizeDataGrid的扩展函数,方便在页面里面进行调用,扩展函数定义如下所示. //datagrid宽度高度自动调整的函数 $.fn.exten

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

在很多Web系统中,一般都可能提供一些图标的选择,方便配置按钮,菜单等界面元素的图标,从而是Web系统界面看起来更加美观和协调.但是在系统中一般内置的图标样式相对比较有限,而且硬编码写到样式表里面,这样给我们扩展使用有很多的不方便.基于这个原因,我想如果能够独立一个模块,自动根据图标生成图标CSS样式文件,并存储相应的记录到数据库里面,方便我们查询显示,那样我们使用起来就很方便了,最后有了这些数据,只需要做一个通用的图标选择界面,并可以在很多地方重用了.本文正是基于这个思路,开发了一个图标管理模

基于MVC4+EasyUI的Web开发框架经验总结(15)--在MVC项目中使用RDLC报表

RDLC是一个不错的报表,有着比较不错的设计模式和展现效果,在我的Winform开发里面,使用RDLC也是一个比较方便操作,如可以参考文章<DevExpress的XtraReport和微软RDLC报表的使用和对比>或者<会员管理系统的设计和开发(2)-- RDLC报表的设计及动态加载>进行了解.但是基于MVC方式,如何构建和展现RDLC报表呢?本文主要介绍如何在基于MVC4+EasyUI的Web开发框架上进行RDLC的集成和使用. 1.RDLC绑定数据源 RDLC的报表设计,是使用

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

在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交,方便页面和服务器后端进行数据的交互处理.本文主要介绍利用Jquery处理数据交互的几种方式,包括获取数据并显示,插入新数据到服务器,更新数据,删除数据等操作. 1.利用Jquery获取数据并显示 为了顺利获取数据,我们需要保持页面端调用和服务器端保持一致,并相应的把数据转换或者封装为对象实体进行处理. 下面我们以一个简单的全国省份.全国城市.全国城市行政区的案例进行Demo代码的介绍.    

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

在Web开发的时候,我们很多时候,需要引用很多CSS文件.JS文件,随着使用更多的插件或者独立样式文件,可能我们的Web界面代码会越来越臃肿,看起来也很累赘,在MVC里面提供了一个Bundle的对象,用来简化页面代码非常方便,本文主要介绍在我的MVC框架里面,如何使用bundles来简化页面的代码的. 1.常规的页面代码 我们知道,随着使用更多的一些效果,我们可能不断引入一些新的JS和CSS文件,已达到Web界面更好的表现效果.这样也就逐步增加了文件代码的行数,造成相对比较臃肿的场景,如下面的我

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

在博客园很多文章里面,曾经有一些介绍Office文档预览查看操作的,有些通过转为PDF进行查看,有些通过把它转换为Flash进行查看,但是过程都是曲线救国,真正能够简洁方便的实现Office文档的预览的还是比较少,这里的Office文档包括了Word.Excel.PPT文档.本文介绍两种方式,一种方式是通过在线预览的方式,利用微软的平台进行Office文档的在线查看:一种是把Office文档生成HTML文件后进行查看.然后对比他们的优缺点,并进行总结. 1.利用微软的平台进行Office文档的在

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

Web开发上有很多HTML的编辑控件,如CKEditor.kindeditor等等,很多都做的很好,本文主要介绍在MVC界面里面,CKEditor的配置和使用.CKEditor的前身是FCKEditor,随着它的更新,上传图片的功能被分离出去了,现在如果需要实现上传图片,要么自己写代码或者采用其他上传控件(如Uploadify),还有一种方法是使用CKFinder,这两者的合并使用,能给我们带来更多的方便. 1.CKEditor的使用 CKEditor的下载地址是http://ckeditor.

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

在我们做各种应用的时候,我们可能都会使用到图表统计,以前接触过一些不同的图表控件,在无意中发现了图表控件Highcharts,其强大的功能和丰富的互动效果,令人难以忘怀.本篇主要介绍在Web开发中使用图表控件Highcharts,以及对其进行统一汉化等操作,让我们的程序功能更加丰富,内容更加美观. 1.Highcharts基础介绍 Highcharts是一个非常流行,界面美观的纯Javascript图表库.它主要包括两个部分:Highcharts和Highstock.Highcharts可以为您

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

我们在使用EasyUI的时候,很多情况下需要使用到表格控件datagrid,这个控件控件非常强大,使用起来很简洁,但是我在使用中,发现对于一个表里面的外键字段进行转义,并显示引用表的一些名称的操作,却显得比较难以实现,找了很多资料,基本上没有找到对应的解决方案.本文主要介绍我对这种外键字段转义的操作的实现方式,以便供大家参考了解. 1.DataGrid的初始化操作 在了解对内容的解析前,我们先来了解EasyUI里面Datagrid的初始化操作过程,然后逐步进行分析,寻求解决方式. 一般情况下,D