zoukankan      html  css  js  c++  java
  • 基于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>

    最后出来的效果,就是博客开始介绍的界面截图,没有任何变化,但是代码我们已经经过了几步的优化整理,看起来很清爽,更能实现动态变化了。

  • 相关阅读:
    工厂模式
    将博客搬至CSDN
    网络安全-跨站脚本攻击XSS(Cross-Site Scripting)
    Linux 权限
    git常用的语句
    git代码提交与克隆
    git学习
    Mybatis常见问题
    关于集合常见的问题
    远程连接(加密验证问题解决)
  • 原文地址:https://www.cnblogs.com/feng-NET/p/4696987.html
Copyright © 2011-2022 走看看