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

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

官网:https://adminlte.io/

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

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

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

由于全套的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源码中复制一些关键的代码,避免写错。

 $(function () {
$.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(i==0){
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];
//这里默认设置第一个子菜单为选中状态
if(j==0){
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);
}
}
} });
});

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

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

要实现这个功能,我们需要在上述的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对象了。

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

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);
}
}
} });
});

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

--会员概览页

---会员添加页

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

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

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

 $(function () {
var firstLvId=getFirstLvMenu();//一级菜单
var secondLvId=getSecondLvMenu();//二级菜单
var thirdLvId=getThirdLvMenu();//三级菜单
$.ajax({
type: 'get',
url:'/menu/tree',
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==firstLvId){
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 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>');
$('[menu-id="'+i+'"]').append(html);
//继续遍历二级菜单
childLen=menu.child.length;
for(var j in menu.child){
child=menu.child[j];
//如果子菜单是该菜单,则设为active选中
if(child.menuId==secondLvId){
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>');
}else{
html=$('<li><a class="second-menu" href="../'+child.menuSrc+'" onclick="saveSecondLvMenu('+child.menuId+')"><i class="fa fa-circle-o"></i>'+child.menuName+'</a></li>');
}
$('[menuUL-id="'+i+'"]').append(html);
}
}
} });
});
function saveFirstLvMenu(menuId) {
var id = JSON.stringify(menuId);
window.sessionStorage.setItem("firstMenuId", id);
} function saveSecondLvMenu(menuId) {
var id = JSON.stringify(menuId);
window.sessionStorage.setItem("secondMenuId", id);
} function saveThirdLvMenu(menuId) {
var id = JSON.stringify(menuId);
window.sessionStorage.setItem("thirdMenuId", id);
} function getFirstLvMenu() {
return JSON.parse(window.sessionStorage.getItem("firstMenuId"));
}
function getSecondLvMenu() {
return JSON.parse(window.sessionStorage.getItem("secondMenuId"));
}
function getThirdLvMenu() {
return JSON.parse(window.sessionStorage.getItem("thirdMenuId"));
}

通用后台管理系统UI模板-AdminLTE简介及构造动态菜单栏的更多相关文章

  1. ASP.NET MVC5+EF6+LayUI实战教程,通用后台管理系统框架(1)

    文章转自:http://www.xuboyi.com/298.html 前言 网站运营有一段时间了,记录的内容都是杂七杂八的,思前想后,决定给大家分享一套ASP.Net的系列教程.手把手的做一套通用后 ...

  2. 分享基于EF+MVC+Bootstrap的通用后台管理系统及架构

      基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用, 提供了OA.CRM.CMS的原型实例,适合快速构建中小型互联网及行业 ...

  3. 分享基于EF+MVC+Bootstrap的通用后台管理系统及架构(转)

    http://www.cnblogs.com/guozili/p/3496265.html 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通 ...

  4. 基于EF+MVC+Bootstrap的通用后台管理系统及架构

    分享基于EF+MVC+Bootstrap的通用后台管理系统及架构 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用, 提供了 ...

  5. asp.net EF+MVC+Bootstrap 通用后台管理系统

    需要源码,请加QQ:858-048-581 开发环境: VS2012或以上 数据库: SQL Server 2008R2或以上   基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级 ...

  6. 通用后台管理系统(ExtJS 4.2 + Spring MVC 3.2 + Hibernate)

    通用后台管理系统(ExtJS 4.2 +Spring MVC 3.2 + Hibernate) 开发语言JAVA 成品成品 前端技术extjs 数据库mysql,sql server,oracle 系 ...

  7. 通用后台管理系统UI-AdminLTE:构造动态菜单栏

    AdminLTE是一款基于bootstrap的后台管理系统的通用模板UI,它的样式美观且较为符合大多数后台管理系统的需求,典型的上|左右|下的布局形式.并且提供了一整套我们开发的时候可能用到的UI样式 ...

  8. 后台管理UI模板

    一.EasyUI easyui是一种基于jQuery的用户界面插件集合. easyui为创建现代化,互动,JavaScript应用程序,提供必要的功能. 使用easyui你不需要写很多代码,你只需要通 ...

  9. vue3后台管理系统(模板)

    系统简介 此管理系统是基于Vite2和Vue3.0构建生成的后台管理系统.目的在于学习vite和vue3等新技术,以便于后续用于实际开发工作中: 本文章将从管理系统页面布局.vue路由鉴权.vuex状 ...

随机推荐

  1. 剑指Offer:链表中环的入口节点【23】

    剑指Offer:链表中环的入口节点[23] 题目描述 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null. 题目分析 第一步确定链表中是否包含环,怎么确定呢?我们定义两个指针橙和 ...

  2. Database: index

    The whole point of having an index is to speed up search queries by essentially cutting down the num ...

  3. centos下安装wordpress

    https://www.jianshu.com/p/2439dc2187b2 https://blog.csdn.net/liuhelong/article/details/79924014

  4. [BZOJ 1095] [ZJOI 2007]Hide 捉迷藏

    在BZ上连续MLE n次后,终于A了. 自己YY的动态点分写法,思路还是很清楚的,但是比较卡内存. 用到了MAP导致复杂度比其他的代码多了一个log,看来需要去借鉴一下别人怎么写的. updata i ...

  5. qemu仿真执行uboot和barebox

    先安装qemu: apt-get install qemu-system 交叉编译器可以选择友善之臂:http://arm9download.cncncn.com/mini2440/linux/arm ...

  6. 2-mybatis框架

    mybatis是一个持久层的框架,是apache下的顶级项目. mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需 ...

  7. matlab之find()函数

    Find 这个函数用处也挺大的,这几天看很多程序都见到这一函数,今天要好好给阐述,了解下这个函数是为了找到矩阵或者是数组,向量中的非零元素.下面一大段英文没耐心看.看看例子就行了. 第一个用法是 nd ...

  8. RQNOJ 95 多多看DVD(加强版):01背包

    题目链接:https://www.rqnoj.cn/problem/95 题意: 叔叔要陪多多看动画片. 有n张DVD可以买,第i张碟的打分为w[i],播放时间为t[i]. 爷爷规定他们只能在一定的时 ...

  9. IDEAL葵花宝典:java代码开发规范插件 p3c

    前言: P3C插件 是阿里巴巴p3c项目组进行研发.这个项目组是阿里巴巴开发爱好者自发组织形成的虚拟项目组,根据<阿里巴巴Java开发规范>转化而成的自动化插件,并且实现了部分自动编程. ...

  10. leetcode 104 Maximum Depth of Binary Tree(DFS)

    Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...