由于后台使用了chen框架,所以代码不能完全列出,可以到http://git.oschina.net/eternal_rider/chen下载项目,运行后,即可看到菜单效果级管理。
示例框架中写了一个jquery菜单插件实现,可以使用存html代码+样式使用,也可以给出json格式数据,以jquery插件方式。
对应json格式,我写了示例代码,从数据库表总读取记录,转成json。sql只要select * from 表 order by 父id,即按照父编号排序,这样生成html时,先生成根节点,然后子节点,孙子节点。。。这样。我也做后台管理,可以在后台添加编辑,前台自动展现,以后会加授权功能。
先看下效果,然后在看代码。
HTML-scheme:
<ul id="menu"> <li><a href="#">chen框架介绍</a></li> <li> <a href="#">设计文档</a> <ul> <li><a href="#">视图层</a></li> <li><a href="#">控制层</a></li> <li><a href="#">模型层</a></li> <li><a href="#">仓储层</a></li> </ul> </li> <li><a href="#">示例项目</a></li> <li><a href="#">后台管理</a></li> </ul>
#menu { width: 100%; margin: 0; padding: 10px 0 0 0; list-style: none; background: #111; background: -moz-linear-gradient(#444, #111); background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #111),color-stop(1, #444)); background: -webkit-linear-gradient(#444, #111); background: -o-linear-gradient(#444, #111); background: -ms-linear-gradient(#444, #111); background: linear-gradient(#444, #111); -moz-border-radius: 50px; border-radius: 50px; -moz-box-shadow: 0 2px 1px #9c9c9c; -webkit-box-shadow: 0 2px 1px #9c9c9c; box-shadow: 0 2px 1px #9c9c9c; } #menu li { float: left; padding: 0 0 10px 0; position: relative; line-height: 0; } #menu a { float: left; height: 25px; padding: 0 25px; color: #999; text-transform: uppercase; font: bold 12px/25px Arial, Helvetica; text-decoration: none; text-shadow: 0 1px 0 #000; } #menu li:hover > a { color: #fafafa; } *html #menu li a:hover /* IE6 */ { color: #fafafa; } #menu li:hover > ul { display: block; } /* Sub-menu */ #menu ul { list-style: none; margin: 0; padding: 0; display: none; position: absolute; top: 35px; left: 0; z-index: 99999; background: #444; background: -moz-linear-gradient(#444, #111); background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #111),color-stop(1, #444)); background: -webkit-linear-gradient(#444, #111); background: -o-linear-gradient(#444, #111); background: -ms-linear-gradient(#444, #111); background: linear-gradient(#444, #111); -moz-box-shadow: 0 0 2px rgba(255,255,255,.5); -webkit-box-shadow: 0 0 2px rgba(255,255,255,.5); box-shadow: 0 0 2px rgba(255,255,255,.5); -moz-border-radius: 5px; border-radius: 5px; } #menu ul ul { top: 0; left: 150px; } #menu ul li { float: none; margin: 0; padding: 0; display: block; -moz-box-shadow: 0 1px 0 #111111, 0 2px 0 #777777; -webkit-box-shadow: 0 1px 0 #111111, 0 2px 0 #777777; box-shadow: 0 1px 0 #111111, 0 2px 0 #777777; } #menu ul li:last-child { -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } #menu ul a { padding: 10px; height: 10px; width: 130px; height: auto; line-height: 1; display: block; white-space: nowrap; float: none; text-transform: none; } *html #menu ul a /* IE6 */ { height: 10px; } *:first-child+html #menu ul a /* IE7 */ { height: 10px; } #menu ul a:hover { background: #0186ba; background: -moz-linear-gradient(#04acec, #0186ba); background: -webkit-gradient(linear, left top, left bottom, from(#04acec), to(#0186ba)); background: -webkit-linear-gradient(#04acec, #0186ba); background: -o-linear-gradient(#04acec, #0186ba); background: -ms-linear-gradient(#04acec, #0186ba); background: linear-gradient(#04acec, #0186ba); } #menu ul li:first-child > a { -moz-border-radius: 5px 5px 0 0; border-radius: 5px 5px 0 0; } #menu ul li:first-child > a:after { content: ''; position: absolute; left: 30px; top: -8px; width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 8px solid #444; } #menu ul ul li:first-child a:after { left: -8px; top: 12px; width: 0; height: 0; border-left: 0; border-bottom: 5px solid transparent; border-top: 5px solid transparent; border-right: 8px solid #444; } #menu ul li:first-child a:hover:after { border-bottom-color: #04acec; } #menu ul ul li:first-child a:hover:after { border-right-color: #04acec; border-bottom-color: transparent; } #menu ul li:last-child > a { -moz-border-radius: 0 0 5px 5px; border-radius: 0 0 5px 5px; } /* Clear floated elements */ #menu:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; } * html #menu { zoom: 1; } /* IE6 */ *:first-child+html #menu { zoom: 1; } /* IE7 */ </style> <!-- AdPacks --> <style> #adpacks-wrapper{font-family: Arial, Helvetica;width:280px;position: fixed;_position:absolute;bottom: 0;right: 20px;z-index: 9999;background: #eaeaea;padding: 10px;-moz-box-shadow: 0 0 15px #444;-webkit-box-shadow: 0 0 15px #444;box-shadow: 0 0 15px #444;} body .adpacks{background:#fff;padding:15px;margin:15px 0 0;border:3px solid #eee;} body .one .bsa_it_ad{background:transparent;border:none;font-family:inherit;padding:0;margin:0;} body .one .bsa_it_ad .bsa_it_i{display:block;padding:0;float:left;margin:0 10px 0 0;} body .one .bsa_it_ad .bsa_it_i img{padding:0;border:none;} body .one .bsa_it_ad .bsa_it_t{padding: 0 0 6px 0; font-size: 11px;} body .one .bsa_it_p{display:none;} body #bsap_aplink,body #bsap_aplink:hover{display:block;font-size:9px;margin: -15px 0 0 0;text-align:right;} body .one .bsa_it_ad .bsa_it_d{font-size: 11px;} body .one{overflow: hidden}
一下为jquery插件方式:
menu.js
(function(jQuery){ jQuery.fn.menu=function(data){ if(typeof data=="string"){ data = eval("("+data+")"); } var jQuerythis=jQuery(this); var jQuerycoldrop=jQuery(document.createElement("ul")).attr("id","menu"); var ids=jQuerythis.attr("id"); jQuerythis.append(jQuerycoldrop); for(var i=0;i<data.length;i++){ var n = data[i]; var jQueryitem=jQuery(document.createElement("li")); if(n.pid==0){ jQuerycoldrop.append(jQueryitem); jQueryitem.html("<a href=\"javascript:void(0);\" onClick=\"goUrl(\'"+n.name+"\',\'"+n.mode+"\',\'"+n.url+"\')\">"+n.name+"</a>").attr({"id":"col_"+ids+"_"+n.id}); }else{ if(jQuery("#col_"+ids+"_"+n.pid).find("ul").length<=0){ jQuery("#col_"+ids+"_"+n.pid).append("<ul></ul>"); jQuery("#col_"+ids+"_"+n.pid).find("ul:first").append(jQueryitem); jQueryitem.html("<a href=\"javascript:void(0);\" onClick=\"goUrl(\'"+n.name+"\',\'"+n.mode+"\',\'"+n.url+"\')\">"+n.name+"</a>").attr({"id":"col_"+ids+"_"+n.id}); }else{ jQuery("#col_"+ids+"_"+n.pid).find("ul:first").append(jQueryitem); jQueryitem.html("<a href=\"javascript:void(0);\" onClick=\"goUrl(\'"+n.name+"\',\'"+n.mode+"\',\'"+n.url+"\')\">"+n.name+"</a>").attr({"id":"col_"+ids+"_"+n.id}); } } } } })(jQuery); function goUrl(title,mode,iurl){ if(iurl == ""){ return; } var h = window.screen.height; var w = window.screen.width; if(mode == "modal"){ window.showModalDialog(iurl,{name:title},"dialogWidth="+w+";dialogHeight="+h+";resizable=true;location=no;toolbar=no;titlebar=no"); }else if(mode == "dialog"){ //open div }else if(mode == "_blank"){ }else{ } }
goUrl函数,可以自己修改为,任意的展现方式,如更新iframe等。
插件方式例子代码:
<!doctype html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>jquery菜单插件</title> <link type="text/css" href="resources/menu/menu.css" rel="stylesheet" /> <script type="text/javascript" src="resources/jquery.min.js"></script> <script type="text/javascript" src="resources/menu/menu.js"></script> <script type="text/javascript"> jQuery(function(){ //jQuery("#mymenu").menu('json数组'),下面为从后台获得 jQuery("#mymenu").menu('${sessionScope.UserInfo.MenuJson}'); }); </script> </head> </head> <body> <div id="mymenu" class="mainMenu"></div> </body> </html>
json格式
[{"id":"1","icon":"","name":"chen框架介绍","pid":"0","leaf":"1","url":"pages/home.jsp","mode":"modal"},{"id":"3f076f9aa6d74220b1f86b33ffb68387","icon":null,"name":"访问日志","pid":"e50d1c568d19412ca1a97d8bdc01629d","leaf":"1","url":"","mode":"modal"},{"id":"2","icon":"","name":"设计文档","pid":"0","leaf":"0","url":"","mode":"modal"},{"id":"79fe85544ed34957a0a638899ba5709e","icon":null,"name":"模块访问日志","pid":"e50d1c568d19412ca1a97d8bdc01629d","leaf":"1","url":"","mode":"modal"},{"id":"3","icon":"","name":"视图层","pid":"2","leaf":"1","url":"","mode":"modal"},{"id":"688881325bd941dc860afd5437c212a6","icon":null,"name":"操作日志","pid":"e50d1c568d19412ca1a97d8bdc01629d","leaf":"1","url":"","mode":"modal"},{"id":"4","icon":"","name":"控制层","pid":"2","leaf":"1","url":"","mode":"modal"},{"id":"e50d1c568d19412ca1a97d8bdc01629d","icon":null,"name":"日志管理","pid":"6","leaf":"0","url":"directory","mode":"modal"},{"id":"6","icon":"","name":"后台管理","pid":"0","leaf":"0","url":"","mode":"modal"},{"id":"7","icon":"","name":"用户管理","pid":"6","leaf":"1","url":"","mode":"modal"},{"id":"8","icon":"","name":"角色管理","pid":"6","leaf":"1","url":"","mode":"modal"},{"id":"9","icon":"","name":"菜单管理","pid":"6","leaf":"1","url":"pages/manager/menu/menuManager.jsp","mode":"modal"},{"id":"10","icon":"","name":"教程分类","pid":"6","leaf":"1","url":"","mode":"modal"},{"id":"11","icon":"","name":"教程分类","pid":"10","leaf":"1","url":"","mode":"modal"},{"id":"12","icon":"","name":"教程管理","pid":"10","leaf":"1","url":"","mode":"modal"}]
id:菜单的编号
icon:菜单图标(这个我还没有加,过几天加上)
name:菜单名称
pid:菜单的父级编号
leaf:是否为叶子节点,即是否目录(这个在后台管理中用到了,如果你不用后台管理,可以忽略)
url:菜单地址
mode:菜单展现方式,如弹出div,弹出新窗口等,具体见goUrl函数。
菜单数据库表,一般结构如下:
后台管理,java
package my.action; import java.util.Map; import my.model.MenuModel; import chen.ioc.Chen; import chen.view.Renderer; import chen.view.TextRenderer; public class MenuAction { public Renderer list(Map<String,Object> args){ MenuModel mmodel = Chen.container.get(MenuModel.class); String jsonStr = mmodel.loadMenuById(args); return new TextRenderer(jsonStr); } public Renderer add(Map<String,Object> args){ MenuModel mmodel = Chen.container.get(MenuModel.class); int n = mmodel.add(args); return new TextRenderer(String.valueOf(n)); } public Renderer edit(Map<String,Object> args){ MenuModel mmodel = Chen.container.get(MenuModel.class); int n = mmodel.edit(args); return new TextRenderer(String.valueOf(n)); } public Renderer delete(Map<String,Object> args){ MenuModel mmodel = Chen.container.get(MenuModel.class); int n = mmodel.delete(args); return new TextRenderer(String.valueOf(n)); } }
package my.model; import java.util.List; import java.util.Map; import net.sf.json.JSONArray; import chen.util.DbUtil; public class MenuModel{ public int add(Map<String,Object> args) { try { return DbUtil.dao.save(this, args); }catch (Exception e) { e.printStackTrace(); return 0; } } public int edit(Map<String,Object> args) { try { return DbUtil.dao.update(this, args, "id=#id#"); }catch (Exception e) { e.printStackTrace(); return 0; } } public int delete(Map<String,Object> args) { try { return DbUtil.dao.delete(this, args, "id=#id#"); }catch (Exception e) { e.printStackTrace(); return 0; } } public String loadAllMenu(Map<String,Object> args) { return this.loadMenu(selectAllMenu,null); } public String loadMenuById(Map<String,Object> args) { if(args.get("id") == null){ args.put("id","0"); } return this.loadMenu(selectMenuById,args); } public String loadMenu(String sql,Map<String,Object> args) { try { List<Map<String, Object>> menus = null; if(args == null){ menus = DbUtil.dao.query(sql); }else{ menus = DbUtil.dao.query(sql,args); } return JSONArray.fromObject(menus).toString(); } catch (Exception e) { e.printStackTrace(); return null; } } private String selectAllMenu = "select id,pid,name,url,leaf,icon,'modal' mode from menu order by ord asc"; private String selectMenuById = "select id,pid,name,url,leaf,icon,'modal' mode,decode(leaf,'1','','closed') state from menu where pid=#id# order by ord asc"; }
<%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://my.oschina.net/eternal/chen" %> <!doctype html> <html> <head> <base href="${c:base()}"> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>菜单管理</title> <%@ include file="/pages/manager/lib.jsp"%> <script type="text/javascript"> var index = 0; $(function(){ $('#MenuGrid').treegrid({ nowrap: false, collapsible:true, fit:true, title:"菜单管理", rownumbers: true, animate:true, url:'ty/menu/list/', idField:'id', treeField:'name', columns:[[ {field:'name',title:'菜单名称',width:300}, {field:'url',title:'访问路径',width:400} ]], onContextMenu: function(e,row){ e.preventDefault(); $(this).treegrid('unselectAll'); $(this).treegrid('select', row.id); if(row.leaf=='1'){ $("#mm_add_menu").attr("disabled","disabled"); $("#mm_add_dir").attr("disabled","disabled"); }else{ $("#mm_add_menu").removeAttr("disabled"); $("#mm_add_dir").removeAttr("disabled"); } $('#cm').menu('show', { left: e.pageX, top: e.pageY }); }, onLoadSuccess:function (row){ if(index++<1){ $('#MenuGrid').treegrid('expandAll'); } } }); }); function getSelected(){ return $('#MenuGrid').treegrid('getSelected'); } function add(flag){ var node = getSelected(); if(node.leaf == '1'){ $.messager.alert('警告', '不能在功能节点上添加!', 'warning'); return; } if(flag == 1){ $('#win').load('pages/manager/menu/moduleCreator.jsp',null,function(){ $(this).window({title: ' 添加目录',iconCls:'icon-add'}); $(this).window('open'); }); }else{ $('#win').load('pages/manager/menu/menuCreator.jsp?fid=aq1',null,function(){ $(this).window({title: ' 添加菜单',iconCls:'icon-add'}); $(this).window('open'); }); } } function dele(){ var node = getSelected(); var b = $('#MenuGrid').treegrid('isLeaf', node.target); if(b){ $.messager.confirm('信息', '是否确认删除[' + node.name + ']?', function(r){ if(r){ $.post('ty/menu/delete/',{id:node.id},function (data){ if(data >= 1){ $('#MenuGrid').treegrid('reload',node.pid); }else{ $.messager.alert('错误', '删除失败,请联系管理员!', 'error'); } }); } }); }else{ $.messager.alert('警告', '请先删除子节点!', 'warning'); } } function edit(){ var node = getSelected(); if(node.leaf==1){ $('#win').load('pages/manager/menu/menuEditor.jsp',{id:node.id},function(){ $(this).window({title: ' 编辑菜单',iconCls:'icon-add'}); $(this).window('open'); }); }else{ $('#win').load('pages/manager/menu/moduleEditor.jsp',null,function(){ $(this).window({title: ' 编辑目录',iconCls:'icon-add'}); $(this).window('open'); }); } } </script> </head> <body topmargin="0" leftmargin="1" rightmargin="1"> <table id="MenuGrid"></table> <div id="cm" class="easyui-menu" style="width: 120px;"> <div id="mm_add_menu" onclick="add()" iconCls="icon-add"> 添加模块 </div> <div id="mm_add_dir" onclick="add()" iconCls="icon-add"> 添加功能 </div> <div class="menu-sep"></div> <div id="mm_dele" onclick="dele()" iconCls="icon-remove"> 删除 </div> <div id="mm_edit" onclick="edit()" iconCls="icon-edit"> 编辑 </div> </div> <div id="win" style="width: 650px; height: 300px; padding: 10px;" closed="true" shadow="true" resizable="false" collapsible="true" minimizable="false" maximizable="false"></div> </body> </html>