一.用layui及mini做一个初步的导航栏加菜单栏框架。
layuimini目前是开源的前端框架。目前有两种思路。第一种是用接口,让layuimini读取接口中的菜单栏初始化,一种是用model映射。
我用的模板引擎是thymeleaf。
1.(制作页面第一种方法)用model映射做导航栏和菜单栏
这种适合有js基础的人,因为很多东西都要参考layuimini的基础重做js,否则无法将导航栏,菜单栏,菜单历史导航同步。先看数据库设计:
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` (
`pk_menu_id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`menu_title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '标题',
`menu_href` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '链接',
`parent_id` bigint(0) NOT NULL COMMENT '父级菜单ID',
`icon` varchar(10000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '图标',
`authority` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限标识符',
`sort` smallint(0) NULL DEFAULT NULL COMMENT '排序值',
`type` tinyint(0) NOT NULL COMMENT '类型[1:目录, 2:菜单, 3:按钮]',
`status` bit(1) NULL DEFAULT NULL COMMENT '是否显示',
`remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
`target` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '页面跳转方式',
`create_by` bigint(0) NULL DEFAULT NULL COMMENT '创建人',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`update_by` bigint(0) NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`pk_menu_id`) USING BTREE,
UNIQUE INDEX `idx_menu_title`(`menu_title`) USING BTREE,
INDEX `idx_menu_pid`(`parent_id`) USING BTREE,
INDEX `idx_menu_sort`(`sort`) USING BTREE,
INDEX `idx_menu_href`(`menu_href`) USING BTREE,
INDEX `idx_menu_authority`(`authority`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 88 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
可用Mybatisplus,然后自己写个递归将菜单栏做成树形json数据结构,返回到前端进行接收。
<resultMap id="MenuResultMap" type="com.coolbusiness.coolbusiness.system.entity.Menu" >
<id column="pk_menu_id" jdbcType="BIGINT" property="pkMenuId"/>
<result column="menu_title" jdbcType="VARCHAR" property="menuTitle"/>
<result column="menu_href" jdbcType="VARCHAR" property="menuHref"/>
<result column="parent_id" jdbcType="BIGINT" property="parentId"/>
<result column="icon" jdbcType="VARCHAR" property="icon"/>
<result column="authority" jdbcType="VARCHAR" property="authority"/>
<result column="sort" jdbcType="SMALLINT" property="sort"/>
<result column="type" jdbcType="TINYINT" property="type"/>
<result column="status" jdbcType="BIT" property="status"/>
<result column="remark" jdbcType="VARCHAR" property="remark"/>
<result column="target" jdbcType="VARCHAR" property="target"/>
<result column="create_by" jdbcType="BIGINT" property="createBy"/>
<result column="create_time" jdbcType="DATE" property="createTime"/>
<result column="update_by" jdbcType="BIGINT" property="updateBy"/>
<result column="update_time" jdbcType="DATE" property="updateTime"/>
</resultMap>
<select id="ListParent" resultMap="MenuResultMap">
select * from sys_menu where type=1
</select>
<select id="ListChildren" resultMap="MenuResultMap" parameterType="integer" >
select * from sys_menu where parent_id=${id}
</select>
JAVA代码部分:
DAO层
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.coolbusiness.coolbusiness.system.entity.Menu;
import com.coolbusiness.coolbusiness.system.entity.sysMenu;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface MenuDao extends BaseMapper<Menu> {
/**
* 获取导航栏的全部内容,用于加载页面
* @return
*/
public List<Menu> ListParent();
/**
* 获取子菜单内容
* @return
*/
public List<Menu> ListChildren(@Param("id") Integer id);
}
service层:
import com.coolbusiness.coolbusiness.Constants.Constant;
import com.coolbusiness.coolbusiness.system.dao.MenuDao;
import com.coolbusiness.coolbusiness.system.entity.Menu;
import com.coolbusiness.coolbusiness.system.entity.sysMenu;
import com.coolbusiness.coolbusiness.system.service.MenuService;
import com.coolbusiness.coolbusiness.system.utils.TreeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* author baiyang
* 2021-10-01
*/
@Transactional
@Service("MenuService")
public class MenuServiceImpl implements MenuService {
@Resource
private MenuDao menuDao;
@Override
public List<Menu> ListAll() {
List<Menu> menuList = menuDao.ListParent();
//获取子节点childrenList
for (Menu menu : menuList){
getChildrenList(menu);
}
return menuList;
}
public void getChildrenList(Menu menu){
List<Menu> children = menuDao.ListChildren(menu.getPkMenuId());
menu.setChildren(children);
if(children.size()>0 && children!=null )
for (Menu menuChild : children){
getChildrenList(menuChild);
}
}
}
controller层:
import com.coolbusiness.coolbusiness.DIYException.BadRequestException;
import com.coolbusiness.coolbusiness.system.entity.Menu;
import com.coolbusiness.coolbusiness.system.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/login")
public class indexController {
@Autowired
private MenuService menuService;
@GetMapping("/index")
public String indexHTML(Model model){
List<Menu> menuList = menuService.ListAll();
if(menuList!=null && menuList.size()>0 ){
model.addAttribute("menuList", menuList);
}else{
throw new BadRequestException("--->你的菜单内容为空,请检查!");
}
return "index";
}
}
前端页面直接在页面中用标签进行接收即可,代码如下:
index.html:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<html>
<head>
<meta charset="utf-8">
<title>layuimini-iframe版 v2 - 基于Layui的后台管理系统前端模板</title>
<meta name="keywords" content="layuimini,layui,layui模板,layui后台,后台模板,admin,admin模板,layui mini">
<meta name="description" content="layuimini基于layui的轻量级前端后台管理框架,最简洁、易用的后台框架模板,面向所有层次的前后端程序,只需提供一个接口就直接初始化整个框架,无需复杂操作。">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no">
<link rel="icon" href="images/favicon.ico">
<link rel="stylesheet" href="/plugin/layuimini-v2/lib/layui-v2.6.3/css/layui.css" media="all">
<link rel="stylesheet" href="/plugin/layuimini-v2/css/layuimini.css?v=2.0.4.2" media="all">
<link rel="stylesheet" href="/plugin/layuimini-v2/css/themes/default.css" media="all">
<link rel="stylesheet" href="/plugin/layuimini-v2/lib/font-awesome-4.7.0/css/font-awesome.min.css" media="all">
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<style id="layuimini-bg-color">
</style>
</head>
<body class="layui-layout-body layuimini-all">
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo layuimini-logo">
</div>
<div class="layuimini-header-content">
<a>
<div class="layuimini-tool"><i title="展开" class="fa fa-outdent" data-side-fold="1"></i></div>
</a>
<!--电脑端头部菜单-->
<ul class="layui-nav layui-layout-left layuimini-header-menu layuimini-pc-show ">
<li th:data-menu="'multi_module_'+${itemStat.index}" th:each="item, itemStat :${menuList}"
th:if="${item.type}==1"
th:class="'layui-nav-item layui-hide-xs ' + (${itemStat.index eq 0} ? 'layui-this' : '')"
th:id="'multi_module_'+${itemStat.index}+'HeaderId'" >
<a href="javascript:;">
<span class="layui-left-nav" th:text="${item.menuTitle}"></span>
</a>
</li>
</ul>
<!--手机端头部菜单-->
<ul class="layui-nav layui-layout-left layuimini-header-menu layuimini-mobile-show">
<li class="layui-nav-item">
<a href="javascript:;"><i class="fa fa-list-ul"></i> 选择模块</a>
<dl class="layui-nav-child layuimini-menu-header-mobile">
<dd th:each="item, itemStat :${menuList}"
th:if="${item.type}==1"
th:class="'menu-dd undefined undefined ' + (${itemStat.index eq 0} ? 'layui-this' : '')">
<a href="javascript:;" th:data-menu="'multi_module_'+${itemStat.index}"
th:id="'multi_module_'+${itemStat.index}+'HeaderId'">
<span class="layui-left-nav" th:text="${item.menuTitle}"></span>
</a>
</dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;" data-refresh="刷新"><i class="fa fa-refresh"></i></a>
</li>
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;" data-clear="清理" class="layuimini-clear"><i class="fa fa-trash-o"></i></a>
</li>
<li class="layui-nav-item mobile layui-hide-xs" lay-unselect>
<a href="javascript:;" data-check-screen="full"><i class="fa fa-arrows-alt"></i></a>
</li>
<li class="layui-nav-item layuimini-setting">
<a href="javascript:;">admin</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;" layuimini-content-href="/plugin/layuimini-v2/page/user-setting.html" data-title="基本资料" data-icon="fa fa-gears">基本资料<span class="layui-badge-dot"></span></a>
</dd>
<dd>
<a href="javascript:;" layuimini-content-href="/plugin/layuimini-v2/page/user-password.html" data-title="修改密码" data-icon="fa fa-gears">修改密码</a>
</dd>
<dd>
<hr>
</dd>
<dd>
<a href="javascript:;" class="login-out">退出登录</a>
</dd>
</dl>
</li>
<li class="layui-nav-item layuimini-select-bgcolor" lay-unselect>
<a href="javascript:;" data-bgcolor="配色方案"><i class="fa fa-ellipsis-v"></i></a>
</li>
</ul>
</div>
</div>
<!--无限极左侧菜单-->
<div class="layui-side layui-bg-black layuimini-menu-left">
<div class="layui-side-scroll">
<ul th:each="item ,itemStat:${menuList}"
th:if="${item.status}==1 "
th:class="'layui-nav layui-nav-tree layui-left-nav-tree ' + (${itemStat.index > 0} ? 'layui-hide' : '')"
th:id="'multi_module_'+${itemStat.index}">
<li th:each="subItem, subStat:${item.children}"
th:if="${subItem.parentId}==${item.pkMenuId} and ${subItem.status}==1 "
th:id="'multi_module_'+${itemStat.index}" class="layui-nav-item menu-li">
<!--th:text="(${subItem.status}=='1'? ' true ':' false ')
+' '+ (${subItem.target}=='1'? ' true ':' false ')
+' '+(${subItem.menuHref}eq'#'? ' true ':' false ')
+ ${subItem.menuTitle}+ ' '+${subStat.size}" th:text的属性是将文本中的内容进行替换,显示 文本内容时不要在li里面放th:text-->
<a th:if="${subItem.status}=='1' and ${subItem.target}=='1' and ${subItem.menuHref} ne '#'"
th:href="${subItem.menuHref}" target="_blank">
<i th:class="'fa '+${subItem.icon}"></i> 
<!-- <cite th:text="{subItem.menuTitle}"></cite> -->
<span class="layui-left-nav" th:text="${subItem.menuTitle} "></span>
</a>
<a th:if="${subItem.status}=='1' and ${subItem.target} == '2' and ${subItem.menuHref} ne '#' "
th:lay-href="${subItem.menuHref}">
<i th:class="'fa '+${subItem.icon}"></i> 
<!-- <cite th:text="${subItem.menuTitle}"></cite> -->
<span class="layui-left-nav" th:text="${subItem.menuTitle}"></span>
</a>
<a th:if="${subItem.menuHref}eq'#'">
<i th:class="'fa '+${subItem.icon}"></i> 
<!-- <cite th:text="${subItem.menuTitle}"></cite> -->
<span class="layui-left-nav" th:text="${subItem.menuTitle}"></span>
</a>
<dl th:if="${not #lists.isEmpty(subItem.children)}" class="layui-nav-child">
<dd th:if="${nextItem.menuHref} ne '#'" th:each="nextItem ,nextItemStat : ${subItem.children}">
<a th:lay-href="${nextItem.menuHref}" th:text="${nextItem.menuTitle}+${nextItem.menuHref}"> </a>
</dd>
<dd th:if="${nextItem.menuHref} eq '#'" th:each="nextItem ,nextItemStat : ${subItem.children}">
<a th:text="${nextItem.menuTitle}"> </a>
<dl th:if="${not #lists.isEmpty(nextItem.children)}" class="layui-nav-child">
<dd th:each="_nextItem, _nextItemStat : ${nextItem.children}">
<a th:lay-href="${nextItem.menuHref}" th:text="${_nextItem.menuTitle} ${nextItem.menuHref}"></a>
</dd>
</dl>
</dd>
</dl>
</li>
</ul>
</div>
</div>
<!-- 初始化加载层 这里要注释了,不然一直加载接口,这个可以通过见接口注释解决,或者是参数在后端写好后可以放开-->
<!-- <div class="layuimini-loader">-->
<!-- <div class="layuimini-loader-inner"></div>-->
<!-- </div>-->
<!--手机端遮罩层-->
<div class="layuimini-make">
</div>
<!-- 移动导航 -->
<div class="layuimini-site-mobile"><i class="layui-icon"></i></div>
<div class="layui-body">
<div class="layuimini-tab layui-tab-rollTool layui-tab" lay-filter="layuiminiTab" lay-allowclose="true">
<ul class="layui-tab-title">
<li class="layui-this" id="layuiminiHomeTabId" lay-id=""></li>
</ul>
<!-- 这里是导航栏 -->
<div class="layui-tab-control">
<li class="layuimini-tab-roll-left layui-icon layui-icon-left"></li>
<li class="layuimini-tab-roll-right layui-icon layui-icon-right"></li>
<li class="layui-tab-tool layui-icon layui-icon-down">
<ul class="layui-nav close-box">
<li class="layui-nav-item">
<a href="javascript:;"><span class="layui-nav-more"></span></a>
<dl class="layui-nav-child">
<dd><a href="javascript:;" layuimini-tab-close="current">关 闭 当 前</a></dd>
<dd><a href="javascript:;" layuimini-tab-close="other">关 闭 其 他</a></dd>
<dd><a href="javascript:;" layuimini-tab-close="all">关 闭 全 部</a></dd>
</dl>
</li>
</ul>
</li>
</div>
<div class="layui-tab-content">
<div id="layuiminiHomeTabIframe" class="layui-tab-item layui-show"></div>
</div>
</div>
</div>
</div>
<script src="/plugin/layuimini-v2/lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<!-- <script src="/plugin/layuimini-v2/js/lay-config.js?v=2.0.0" charset="utf-8"</script> -->
<script src="/js/common.js" charset="uft-8"></script>
<script src="/js/lib/Tab.js" charset="utf-8"></script><!-- 这里是导入自己写的js啦。不过内容就是将layuimini提供的内荣拿下来改改,其实可以自己跟着写的 -->
</body>
</html>
js部分:
layui.use(['jquery', 'layer'], function () {
var $ = layui.jquery,
layer = layui.layer;
/**
* 菜单模块切换
*/
$('body').on('click', '[data-menu]', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var menuId = $(this).attr('data-menu');
// header
$(".layuimini-header-menu .layui-nav-item.layui-this").removeClass('layui-this');
$(this).addClass('layui-this');
// left
$(".layuimini-menu-left .layui-nav.layui-nav-tree").addClass('layui-hide');
$(".layuimini-menu-left .layui-nav.layui-nav-tree.layui-hide").removeClass('layui-this');
$("#" + menuId).removeClass('layui-hide');
$("#" + menuId).addClass('layui-this');
layer.close(loading);
});
/**
* 菜单缩放
*/
$('body').on('click', '.layuimini-site-mobile', function () {
var loading = layer.load(0, {shade: false, time: 1 * 10});
var isShow = $('.layuimini-tool [data-side-fold]').attr('data-side-fold');
if (isShow == 1) { // 缩放
$('.layuimini-tool [data-side-fold]').attr('data-side-fold', 0);
$('.layuimini-tool [data-side-fold]').attr('class', 'fa fa-indent');
$('.layui-layout-body').removeClass('layuimini-all');
$('.layui-layout-body').addClass('layuimini-mini');
} else { // 正常
$('.layuimini-tool [data-side-fold]').attr('data-side-fold', 1);
$('.layuimini-tool [data-side-fold]').attr('class', 'fa fa-outdent');
$('.layui-layout-body').removeClass('layuimini-mini');
$('.layui-layout-body').addClass('layuimini-all');
layer.close(window.openTips);
}
element.init();
layer.close(loading);
});
/**
* 菜单缩放
*/
$('body').on('click', '[data-side-fold]', function () {
var loading = layer.load(0, {shade: false, time: 1 * 10});
var isShow = $('.layuimini-tool [data-side-fold]').attr('data-side-fold');
if (isShow == 1) { // 缩放
$('.layuimini-tool [data-side-fold]').attr('data-side-fold', 0);
$('.layuimini-tool [data-side-fold]').attr('class', 'fa fa-indent');
$('.layui-layout-body').removeClass('layuimini-all');
$('.layui-layout-body').addClass('layuimini-mini');
// $(".menu-li").each(function (idx,el) {
// $(el).addClass("hidden-sub-menu");
// });
} else { // 正常
$('.layuimini-tool [data-side-fold]').attr('data-side-fold', 1);
$('.layuimini-tool [data-side-fold]').attr('class', 'fa fa-outdent');
$('.layui-layout-body').removeClass('layuimini-mini');
$('.layui-layout-body').addClass('layuimini-all');
// $(".menu-li").each(function (idx,el) {
// $(el).removeClass("hidden-sub-menu");
// });
layer.close(window.openTips);
}
element.init();
layer.close(loading);
});
/**
* 手机端点开模块
*/
$('body').on('click', '.layuimini-header-menu.layuimini-mobile-show dd', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var check = $('.layuimini-tool [data-side-fold]').attr('data-side-fold');
if(check === "1"){
$('.layuimini-site-mobile').trigger("click");
element.init();
}
layer.close(loading);
});
});
然后就会形成大家看到页面效果:
2.LAYUImini制作导航栏和菜单栏(LAYUIMINI文档是有案例可以参考的)
官方写菜单接口的案例,亲测是可用的:点击这里查看即可
本着简单就可的原则,我是不希望所有的东西都要自己写js,真的很累,直接在后端传所有数据到前端即可。我在测试官方文档给我的案例后,改改代码就可以用了,看这里
框框中的方法如下,你直接黏贴使用即可。
function getProjectUrl() { /* 获取你的访问地址前缀 */
var layuiDir = layui.cache.dir;
if (!layuiDir) {
var js = document.scripts, last = js.length - 1, src;
for (var i = last; i > 0; i--) {
if (js[i].readyState === 'interactive') {
src = js[i].src;
break;
}
}
var jsPath = src || js[last].src;
layuiDir = jsPath.substring(0, jsPath.lastIndexOf('/') + 1);
}
return layuiDir.substring(0, layuiDir.indexOf('assets'));
}
然后就会得到一下的结果: