168

通用后台管理系统UI模板-AdminLTE简介及构造动态菜单栏 - xdxxdx

 6 years ago
source link: https://www.cnblogs.com/roy-blog/p/8280933.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

通用后台管理系统UI模板-AdminLTE简介及构造动态菜单栏 - xdxxdx - 博客园

xdxxdx

www.xdxxdxxdx.com

随笔 - 151,  文章 - 0,  评论 - 30,  阅读 -

33万

AdminLTE是一款基于bootstrap的后台管理系统的通用模板UI,它的样式美观且较为符合大多数后台管理系统的需求,典型的上|左右|下的布局形式。并且提供了一整套我们开发的时候可能用到的UI样式,比如表格,表单,图表,日历等。非常适合像我这样对样式编排不太擅长的后端开发者。有了它,我们可以不用自己去写很多复杂的html,css。而把更多时间和精力留在后台的开发上。

话不多说,接下来我简要的介绍一下这款模板UI框架的用法。

官网:https://adminlte.io/

该款框架是免费的,可以直接在官网下载,下载下来的文件大概有50多兆,包含了所有的html,css,js,还有很多的demo。可供我们随时查阅学习。

先来看看整体的UI的风格吧,是不是挺炫酷的。

998564-20180113215052457-1738862642.png

可以说几乎所有的后台需要用到的样式都可以从中寻找得到。

由于全套的UI都是静态数据,所以本篇文章着重介绍一下如何动态构造左侧的菜单栏。这应该也是大家比较关心的问题。

所谓的动态就是指的是从数据库或者文件,或者内存中取到的数据。

本人习惯将菜单的数据写成一个静态的js文件,放在项目的js目录中,这样做的好处是不必每次都去从数据库请求,减少IO操作造成的性能和时间损失,当然你也可以从数据库去请求,甚至把菜单数据放入到redis等内存数据库。各类方法都不影响我们前端代码的编写,因为传递的数据格式都是json.

1.将菜单数据写入一个json文件,代码如下。该文件的路径为webapp/static/json/menu.json。

[{
"menuId":"1",
"name": "基本信息",
"controller":"#",
"child": []
},{
"menuId":"2",
"name": "会员管理",
"controller":"#",
"child": [{
"menuId":"3",
"pMenuId":"2",
"name": "会员概览",
"controller":"user/home"
},{
"menuId":"4",
"pMenuId":"2",
"name": "添加会员",
"controller":"user/add"
}]
},{
"menuId":"5",
"name": "销售管理",
"controller":"#",
"child": [{
"menuId":"5",
"pMenuId":"6",
"name": "销售返佣",
"controller":"post/home"
},{
"menuId":"5",
"pMenuId":"7",
"name": "销售报表",
"controller":"post/add"
}]
}]

至于如何写入到文件,我们可以在每次修改菜单以后,先获取菜单的json数据,然后调用如下代码来将菜单的json数据写入文件。

    public void generateMenuJson(String jsonStr) {
        try {
            File f = new File(ServletActionContext.getServletContext()
                    .getRealPath("/static/json") + "/menu.json");
            if (!f.exists()) {
                f.createNewFile();
            }
            // 定义编码
            OutputStreamWriter write = new OutputStreamWriter(
                    new FileOutputStream(f), "UTF-8");
            BufferedWriter writer = new BufferedWriter(write);
            writer.write(jsonStr);
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.前台ajax获取json数据,并且动态构造出html元素及样式。

主要是用了jQuery ajax异步获取数据,还有就是jquery的append()方法,代码没有什么高深的,只是拼接的时候要很认真。一个取巧的方法是去下载下来的html源码中复制一些关键的代码,避免写错。

 1 $(function () {
 2     $.ajax({
 3         type: 'get',
 4         url:'static/json/menu.json',
 5         dataType:'json',
 6         success:function(data){
 7             var menu=null;
 8             var html=null;
 9             var childLen=null;
10             var child=null;
11             var json=data;
12             console.log(json);
13             for(var i in json){
14                 menu=json[i];
15                 //这里默认展开第一个主菜单
16                 if(i==0){
17                     html=$('<li menu-id="'+i+'" class="active treeview "><li>');
18                 }else{
19                     html=$('<li menu-id="'+i+'" class="treeview "><li>');
20                 }
21                 $(".sidebar .sidebar-menu").append(html);
22                 html=$('<a href="'+menu.controller+'"><i class="fa fa-dashboard"></i> <span>'+menu.name+'</span><span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i></span></a><ul menuUL-id="'+i+'" class="treeview-menu"></ul>');
23                 $('[menu-id="'+i+'"]').append(html);
24                 //继续遍历二级菜单
25                 childLen=menu.child.length;
26                 for(var j in menu.child){
27                     child=menu.child[j];
28                     //这里默认设置第一个子菜单为选中状态
29                     if(j==0){
30                             html=$('<li class="active"><a href="'+child.controller+'"><i class="fa fa-circle-o"></i>'+child.name+'</a></li>');
31                     }else{
32                             html=$('<li><a href="'+child.controller+'"><i class="fa fa-circle-o"></i>'+child.name+'</a></li>');
33                     }            
34                     $('[menuUL-id="'+i+'"]').append(html);
35                 }
36             }
37         }
38     
39 });
40 });

相信大家对照demo中的html源码,可以很容易的理解上述代码。我们把原来的左侧菜单的静态html注释掉,引入上述的js文件。看看效果。

998564-20180113222554191-935451839.png

这样基本实现了菜单显示的效果。但是还有一个缺点,就是菜单不能根据页面动态变换样式,比如我们在会员概览页面,此时展开的是会员管理,选中的是会员概览。而当我们到了销售管理的时候,我们又希望此时菜单能展开销售管理主菜单并选中相应的子菜单。

要实现这个功能,我们需要在上述的js代码中传入当前访问的链接的菜单id,以及其父级菜单id(如果是最上层的菜单,则其父菜单为自己)。然后根据这两个参数来进行菜单是否展开即是否选中的判断。具体步骤如下。

1.菜单实体如下

package com.wonyen.entity;

public class TMenu {
    private int menuId;//菜单编号
    private int pMenuId;//父菜单编号
    private String name;//菜单名称
    private String controller;//菜单对应的controller
    public int getMenuId() {
        return menuId;
    }
    public void setMenuId(int menuId) {
        this.menuId = menuId;
    } public int getpMenuId() { return pMenuId; } public void setpMenuId(int pMenuId) { this.pMenuId = pMenuId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getController() { return controller; } public void setController(String controller) { this.controller = controller; } }

2.获取当前菜单对象,并传入到前台。以会员概览页面为例,代码如下。第8行获取了当前的菜单对象,第9行将其传入到ModelAndView对象中,我们就可以在转发的jsp页面中拿到这个menu对象了。

 1     @RequestMapping("partnerHome")
 2     public ModelAndView partnerHome(ParamModel pm) {
 3         ModelAndView mv = new ModelAndView("back/partner/PartnerList");
 4         mv.addObject("pm", pm);
 5         List<TPartnerLevel> partnerLevelList = partnerLevelService
 6                 .getPartnerLevelList();
 7         mv.addObject("partnerLevelList", partnerLevelList);
 8         TMenu menu=menuService.getMenuByController("partnerHome");//获取当前的菜单信息
 9         mv.addObject("menu", menu);
10         return mv;
11     }

3.在每个页面body加入两个属性,menu_id和p_menu_id.如下所示。

<body class="hold-transition skin-red sidebar-mini" menu_id="${menu.menuId}" p_menu_id="${menu.pMenuId}">

4.重新改写原来js代码,让其支持根据当前页面来变换选中的菜单。

$(function () {
    var menu_id=$('body').attr('menu_id');//菜单id
    var p_menu_id=$('body').attr('p_menu_id');//父级菜单id
    $.ajax({
        type: 'get',
        url:'static/json/menu.json',
        dataType:'json',
        success:function(data){
            var menu=null;
            var html=null;
            var childLen=null;
            var child=null;
            var json=data;
            console.log(json);
            for(var i in json){
                menu=json[i];
                //如果父菜单是该菜单,就展开
                if(menu.menuId==p_menu_id){
                    html=$('<li menu-id="'+i+'" class="active treeview "><li>');
                }else{
                    html=$('<li menu-id="'+i+'" class="treeview "><li>');
                }
                $(".sidebar .sidebar-menu").append(html);
                html=$('<a href="'+menu.controller+'"><i class="fa fa-dashboard"></i> <span>'+menu.name+'</span><span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i></span></a><ul menuUL-id="'+i+'" class="treeview-menu"></ul>');
                $('[menu-id="'+i+'"]').append(html);
                //继续遍历二级菜单
                childLen=menu.child.length;
                for(var j in menu.child){
                    child=menu.child[j];
                    //如果子菜单是该菜单,则设为active选中
                    if(child.menuId==menu_id){
                            html=$('<li class="active"><a href="'+child.controller+'"><i class="fa fa-circle-o"></i>'+child.name+'</a></li>');
                    }else{
                            html=$('<li><a href="'+child.controller+'"><i class="fa fa-circle-o"></i>'+child.name+'</a></li>');
                    }            
                    $('[menuUL-id="'+i+'"]').append(html);
                }
            }
        }
    
});
});

经过上述步骤以后,我们就可以得到更为合理的左侧菜单了。来看看效果吧。

--会员概览页

998564-20180114000342972-1923272088.png

---会员添加页

998564-20180114000512176-1424497235.png

看,已经实现了我们想要的效果。如果你也正在寻找一个后台的UI,赶紧试试吧。

-----------------------------------------------------------------------------------------------2018年4月2日更新-------------------------------------------------------------------------------------------------------------------------------------------------------------------

最近发现一种新的记录菜单选中情况的方法,就是利用浏览器的缓存,每次点击菜单的时候,将点击的菜单Id记录到浏览器缓存中,然后加载菜单的时候通过缓存中的菜单来比对,匹配成功就将其展开并且设为active.这种方法就不需要在服务端传入当前的菜单了,简单了很多。

 1 $(function () {
 2     var firstLvId=getFirstLvMenu();//一级菜单
 3     var secondLvId=getSecondLvMenu();//二级菜单
 4     var thirdLvId=getThirdLvMenu();//三级菜单
 5     $.ajax({
 6         type: 'get',
 7         url:'/menu/tree',
 8         dataType:'json',
 9         success:function(data){
10             var menu=null;
11             var html=null;
12             var childLen=null;
13             var child=null;
14             var json=data;
15             console.log(json);
16             for(var i in json){
17                 menu=json[i];
18                 //如果父菜单是该菜单,就展开
19                 if(menu.menuId==firstLvId){
20                     html=$('<li menu-id="'+i+'" class="active treeview "><li>');
21                 }else{
22                     html=$('<li menu-id="'+i+'" class="treeview "><li>');
23                 }
24                 $(".sidebar .sidebar-menu").append(html);
25                 html=$('<a class="first-menu" href="../'+menu.menuSrc+'" onclick="saveFirstLvMenu('+menu.menuId+')"><i class="fa fa-dashboard"></i> <span>'+menu.menuName+'</span><span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i></span></a><ul menuUL-id="'+i+'" class="treeview-menu"></ul>');
26                 $('[menu-id="'+i+'"]').append(html);
27                 //继续遍历二级菜单
28                 childLen=menu.child.length;
29                 for(var j in menu.child){
30                     child=menu.child[j];
31                     //如果子菜单是该菜单,则设为active选中
32                     if(child.menuId==secondLvId){
33                             html=$('<li class="active"><a class="second-menu" href="../'+child.menuSrc+'" onclick="saveSecondLvMenu('+child.menuId+')"><i class="fa fa-circle-o"></i>'+child.menuName+'</a></li>');
34                     }else{
35                             html=$('<li><a class="second-menu" href="../'+child.menuSrc+'" onclick="saveSecondLvMenu('+child.menuId+')"><i class="fa fa-circle-o"></i>'+child.menuName+'</a></li>');
36                     }            
37                     $('[menuUL-id="'+i+'"]').append(html);
38                 }
39             }
40         }
41     
42 });
43 });
44 function saveFirstLvMenu(menuId) {
45     var id = JSON.stringify(menuId);
46      window.sessionStorage.setItem("firstMenuId", id);
47 }
48 
49 function saveSecondLvMenu(menuId) {
50     var id = JSON.stringify(menuId);
51      window.sessionStorage.setItem("secondMenuId", id);
52 }
53 
54 function saveThirdLvMenu(menuId) {
55     var id = JSON.stringify(menuId);
56      window.sessionStorage.setItem("thirdMenuId", id);
57 }
58 
59 function getFirstLvMenu() {
60     return JSON.parse(window.sessionStorage.getItem("firstMenuId"));
61 }
62 function getSecondLvMenu() {
63     return JSON.parse(window.sessionStorage.getItem("secondMenuId"));
64 }
65 function getThirdLvMenu() {
66     return JSON.parse(window.sessionStorage.getItem("thirdMenuId"));
67 }

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK