前言
搭建完生产环境,接下来进行后台管理系统页面的设计。目前自己的学习重点和知识领域主要还是在后端,但是前端有很多框架,或者说很多适合后端程序员使用的框架,比如easyUI、Boostrap等,能够在前端知识有限的情况下完成一些简单的开发。这里我选择了Layui进行后台管理页面的编写。Layui提供了很多组件拿来就用,风格也非常简洁,且文档友好,很适合快速开发。这是官网提供的文档:layui开发使用文档。
主要功能
- 登录(前后台跨域单点登录)、注销、密码修改
- 博客增、删、查、改
- 博客类别增、删、查、改
- 评论删、查
登录页面(login.jsp)
首先下载Layui:点此下载,解压,然后把压缩包里面的layui文件夹移到项目的statics文件夹下:
接着在spring-mvc.xml里配置静态资源映射,加上这一条:
<mvc:resources location="/WEB-INF/statics/layui/" mapping="/layui/**"/>
为了方便测试我们写一个Controller:
package com.vansl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author: vansl
* @create: 18-3-24 下午12:49
*/
@Controller
public class LoginController {
@RequestMapping("login")
public String login(){
return "login";
}
}
首先先把html大致框架搭好:
<%--
Created by IntelliJ IDEA.
User: vansl
Date: 18-3-24
Time: 下午12:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta charset="utf-8">
<title>登录</title>
<link rel="stylesheet" href="/layui/css/layui.css" media="all" />
<style>
html,body{
height: 100%;
margin: 0 auto;
padding: 0;
position: relative;
background-image: url("/images/login_bg2.jpg");
background-size: cover;
}
.wrapper{
position: absolute;
left:0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
width: 500px;
height: 300px;
}
.head img{
position: absolute;
left:0;
right: 0;
margin: auto;
height: 50px;
}
.main{
position: relative;
top: 60px;
height: 240px;
}
</style>
</head>
<body >
<div class="wrapper">
<div class="head">
<img src="/images/login_ico.png" />
</div>
<div class="main">
</div>
</div>
</body>
</html>
然后在在main这个div里面加上Layui提供的表单控件,在这之前需要引入Layui的css文件:
<link rel="stylesheet" href="/layui/css/layui.css" media="all" />
根据文档说明,只需要引入这一个css文件就可以了,依赖关系已经处理好。
html代码:
<div class="main">
<!--<fieldset>-->
<form class="layui-form" name="loginForm">
<div class="layui-form-item">
<input class="layui-input" type="text" name="username" autocomplete="off" placeholder="用户名" lay-verify="require" />
</div>
<div class="layui-form-item">
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码" lay-verify="require" />
</div>
<div class="layui-form-item captcha">
<img src="/images/cap.png" onclick="this.src=''" />
<input class="layui-input" type="text" name="captcha" autocomplete="off" placeholder="请输入验证码" lay-verify="require" />
</div>
<div class="layui-form-item">
<button class="layui-btn layui-btn-normal" lay-submit="" lay-filter="go">登录</button>
</div>
</form>
<!--</fieldset>-->
</div>
为了界面更美观添加一些样式上去:
<style>
html,body{
height: 100%;
margin: 0 auto;
padding: 0;
position: relative;
background-image: url("/images/login_bg2.jpg");
background-size: cover;
}
.wrapper{
position: absolute;
left:0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
width: 500px;
height: 300px;
}
.head img{
position: absolute;
left:0;
right: 0;
margin: auto;
height: 50px;
}
.main{
position: relative;
top: 60px;
height: 240px;
}
.layui-form-item{
position: relative;
text-align: center;
margin-top: 15px;
left: 20%;
width: 60%;
}
input{
color: white ;
background: none !important;
}
.captcha>img{
float: right;
width: 40%;
height: 38px;
cursor:pointer;
}
.captcha>input{
width: 60%;
}
</style>
把图片都放好之后,最后呈现出来的效果图如下:
最后是js代码,引入Layui的js文件,然后做一些简单的表单验证、ajax请求登录等任务:
<script type="text/javascript" src="/layui/layui.js"></script>
<script>
layui.use(['layer', 'form'], function() {
//加载所需模块
var layer = layui.layer,
form = layui.form,
$ = layui.jquery;
//表单验证
form.verify({
require:function(value,item){
if(item.name=="username"&&value==""){
return "请输入用户名";
}else if(item.name=="password"&&value==""){
return "请输入密码";
}else if(item.name=="captcha"&&value==""){
return "请输入验证码";
}
}
});
//ajax请求登录,登录成功则跳转到后台管理页面,否则刷新验证码
form.on('submit(go)', function(data){
$.ajax({
url:"/check",
contentType: "application/json; charset=utf-8",
data:JSON.stringify(data.field),
type: "post",
success:function(result){
result=JSON.parse(result)
if(result.info==="success"){
location.replace("/admin");
}else{
if(result.info==="error"){
layer.alert('系统错误', {icon: 2});
}else if(result.info==="wrong"){
layer.alert('用户名或密码密码错误', {icon: 2});
}else if(result.info==="denied"){
layer.alert('权限不足', {icon: 2});
}else{
layer.alert(result.info, {icon: 2});
}
//请求新的验证码
$(".captcha img").attr("src","");
}
}
});
return false;
});
});
</script>
登录页完成,接下来就是后台管理页面了。
后台管理页面(admin.jsp):
首先仍然是先把基本的框架搭起来,这里我直接使用了Layui官方提供的示例:后台布局,在此基础上稍加修改并根据博客系统的需求更改各项标签,代码如下:
<%--
Created by IntelliJ IDEA.
User: vansl
Date: 18-3-25
Time: 下午5:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>博客后台管理</title>
<link rel="stylesheet" href="/layui/css/layui.css">
<style>
.layui-layout-admin .layui-header {
background-color: #4E5465;
}
.layui-logo img{
height:40px;
margin-right: 10px;
}
.layui-layout-left{
padding: 0;
}
#searchInput,#searchScope,#searchBtn{
margin-left:30px;
}
</style>
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo"><img src="/images/config_ico.svg" />后台管理系统</div>
<!-- 水平导航) -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item" lay-unselect="" id="switchNav">
<a href="javascript:;"><i class="layui-icon"></i></a>
</li>
<li class="layui-nav-item" lay-unselect="" id="searchInput">
<input class="layui-input" name="search" autocomplete="off">
</li>
<li class="layui-nav-item" id="searchScope">
<a href="javascript:;">文章</a>
<dl class="layui-nav-child layui-anim layui-anim-upbit">
<dd><a href="">评论</a></dd>
<dd><a href="">分类</a></dd>
</dl>
</li>
<li class="layui-nav-item" lay-unselect="" id="searchBtn">
<button class="layui-btn search-btn"><i class="layui-icon"></i>搜索</button>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">
<!--<img src="http://t.cn/RCzsdCq" class="layui-nav-img">-->
vansl
</a>
<dl class="layui-nav-child">
<dd><a href="">修改密码</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a href="">注销</a></li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航 -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;">博客管理</a>
<dl class="layui-nav-child">
<dd><a href="javascript:;">写博客</a></dd>
<dd><a href="javascript:;">文章管理</a></dd>
</dl>
</li>
<li class="layui-nav-item layui-nav-itemed"><a href="javascript:;">评论管理</a></li>
<li class="layui-nav-item layui-nav-itemed"><a href="javascript:;">个人分类管理</a></li>
</ul>
</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
</div>
<div class="layui-footer">
<!-- 底部固定区域 -->
Copyright © 2018 myblog
</div>
</div>
<script src="/layui/layui.js"></script>
<script src="/js/admin.js"></script>
</body>
</html>
呈现的效果如下:
html页面的大致框架搭起来以后,分步来完成以下这几个主要功能模块:左侧菜单栏的收缩、内容主体区域(数据表格和富文本编辑器)、ajax前后台的交互(初步代码)。由于js的内容会比较多,把js代码放在单独的文件admin.js里。
- 左侧菜单栏的收缩
用到了jQuery的animate()方法,实现起来比较简单,代码如下:
layui.use(['layer','element'], function(){
//加载所需模块
var layer = layui.layer,
element = layui.element,
$ = layui.jquery;
i=0; //定义一个变量i以判断动画收缩
$('#switchNav').click(function(){
if(i==0){
$(".layui-side").animate({width:'toggle'});
$(".layui-body").animate({left:'0px'});
$(".layui-footer").animate({left:'0px'});
//更换指示图标方向
$("#switchNav .layui-icon").text("\ue65b");
i++;
}else{
$(".layui-side").animate({width:'toggle'});
$(".layui-body").animate({left:'200px'});
$(".layui-footer").animate({left:'200px'});
//更换指示图标方向
$("#switchNav .layui-icon").text("\ue65a");
i--;
}
});
});
- 内容主体区域(数据表格和富文本编辑器)
首先是数据表格,分别对应三个功能有三张表:文章、评论、分类,使用Layui提供的表格组件:数据表格。点击左边的导航兰之后,页面的主体内容就切换成相应的表格或富文本编辑器。在这一过程中只有页面主体内容区域的变化,不需要重新加载整个页面,用ajax做局部刷新即可(题外话:包括使用ajax在内的单页面应用一个明显的缺点就无法前进后退(后台管理页面不用考虑搜索引擎seo),前端路由技术可以解决这个缺点,具体实现有hash和html5 history api两种方案:前端路由的两种实现原理。但是考虑到是后台页面结构较为简单,且项目重点在后端,我没有使用前端路由,以后看情况再继续完善)。以文章管理页面为例,在statics文件夹下新建html文件夹,然后创建一个静态html页面:
<div style="padding: 15px;">
<table id="blog_table" lay-filter="blog_table"></table>
</div>
<!-- 博客管理工具条渲染模版-->
<script type="text/html" id="blog_table_bar">
<a class="layui-btn layui-btn-xs" lay-event="view">查看</a>
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-xs" lay-event="type">分类</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
<script id="parseTime" type="text/html">
{{parseTime(d.time)}}
</script>
<script type="text/javascript">
function parseTime(time){
var date = new Date(time);//如果date为13位不需要乘1000
var Y = date.getFullYear() + '-';
var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '-';
var D = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate()) + ' ';
var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
var m = (date.getMinutes() <10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
var s = (date.getSeconds() <10 ? '0' + date.getSeconds() : date.getSeconds());
return Y+M+D+h+m+s;
}
</script>
<style>
div.layui-layer-content{
overflow:visible !important;
}
</style>
<script type="text/html" id="typeSelect">
<form class="layui-form layui-form-pane" id="typeForm">
<div class="layui-form-item">
<label class="layui-form-label">请选择分类</label>
<div class="layui-input-inline">
<select name="category" id="category" lay-filter="category">
</select>
</div>
<div class="layui-input-inline">
<select name="type" id="type" lay-filter="type">
</select>
</div>
</div>
</form>
</script>
<!-- 引入分类选择渲染js -->
<script type="text/javascript" src="/js/type_select.js"></script>
<script>
var blogData;
//文章管理表格
layui.table.render({
elem: '#blog_table',
width: 1200,
url: '/blog/?userId='+'1', //数据接口
done: function(res, curr, count){
blogData=JSON.stringify(res);
},
page: true , //开启分页
request: {
pageName: 'offset' //页码的参数名称,默认:page
,limitName: 'limit' //每页数据量的参数名,默认:limit
},
cols: [[ //表头
{field: 'title', title: '标题', width: 420},
{field: 'time', title: '上传时间', width: 180,sort: true,templet: '#parseTime'},
{field: 'pv', title: '阅读量', width: 100},
{field: 'typeName', title: '分类', width: 200, sort: true},
{field: 'published', title: '状态', width: 100,templet:function (d) {
return d.published==0?'已发表':'草稿';
}},
{title:'操作',align:'center',width: 200,toolbar:'#blog_table_bar'}
]]
});
//文章表格工具条事件监听
layui.table.on('tool(blog_table)', function(obj){ //tool是工具条事件名,参数是table原始容器的lay-filter属性值
var layEvent = obj.event; //获得 lay-event 对应的值
if(layEvent === 'del'){ //删除
layer.confirm('确定要删除该文章吗?', function(index){
layer.close(index);
layer.load(1);
//向服务器发送删除文章请求
layui.jquery.ajax({
url:"/blog/"+obj.data.id,
type: "DELETE",
data:JSON.stringify({
"userId":1
}),
contentType: "application/json; charset=utf-8",
success:function (result) {
layer.closeAll('loading');//关闭loading图标
layer.msg("删除成功", {icon: 1});
obj.del(); //删除表格对应行并更新缓存
},
error:function (result) {
layer.closeAll('loading');
layer.msg(result.responseText, {icon: 2});
}
})
});
}else if(layEvent == 'view'){
window.open("/article/"+obj.data.id);
}else if(layEvent == 'type'){
//请求所选文章分类信息并初始化分类选择面板
layui.jquery.ajax({
url: "/type/"+obj.data.typeId,
type: "get",
dataType: "json",
success: function (result) {
initCategoty(result.id,result.children?result.children[0].id:null);
}
});
//渲染模版视图
var view = typeSelect.innerHTML;
data={};
layui.laytpl(view).render(data,function(html){
view=html;
});
layer.open({
type: 1 , //Page层类型,
btn:['确认'], //按钮
btnAlign: 'c',//按钮居中排列
title: "选择分类",
area: ['600px', 'auto'],
skin: 'layui-layer-prompt',
shade: 0.6, //遮罩透明度
maxmin: true, //允许全屏最小化
anim: 5 , //0-6的动画形式,-1不开启
content:view,
//向服务器发送更新文章分类请求
yes: function(index){
layui.jquery.ajax({
url: "/blog/"+obj.data.id,
type: "PUT",
data:JSON.stringify({
"typeId":typeId?typeId:categoryId,
"userId":1
}),
contentType: "application/json; charset=utf-8",
success: function (result) {
//更新表格分类数据
obj.update({
typeName:layui.jquery("#type").val()?layui.jquery("#type").val():layui.jquery("#category").val(),
typeId:typeId?typeId:categoryId
});
layer.msg('编辑分类成功', {icon: 1});
layer.close(index);
},
error:function(result){
layer.msg(result.responseText, {icon: 2});
}
});
}
});
}else if(layEvent == 'edit'){
//保存要编辑的博客信息后跳转到写博客页面
window.editBlogInfo={
blogId:obj.data.id,
title:obj.data.title,
typeId:obj.data.typeId
};
layui.jquery("div.layui-side dd:nth-child(1) > a").click();
}
});
</script>
表格和工具条的创建、事件监听在Layui文档里都有详细说明。接着在spring-mvc.xml里配置html文件的静态资源映射:
<mvc:resources location="/WEB-INF/statics/html/" mapping="/html/**"/>
在admin.jsp的左侧导航栏标签上绑定加载函数,增加一个class属性"layui-this"显示默认选中,并在admin.js里调用load函数以初始化页面:
<dd class="layui-this"><a href="javascript:load('blog');">文章管理</a></dd>
加载函数,使用jQuery进行ajax局部刷新:
function load(view) {
layui.jquery(".layui-body").load("/html/"+view+"_admin.html",function(){});
}
最后根据上面表格创建里代码的接口地址以及Layui文档在js文件夹下新建一个testTable.json文件,放入相应的数据测试,显示页面如下:
评论管理也是一样的流程,这里不再赘述。
然后是个人分类管理页面。在数据库里博客分类表设计成可无限扩展模式,为了显示方便打算之后在后端限制分类的级数,前端同样容易为了实现我做成如下模仿省市区三级联动+弹框编辑的效果:
实际使用中发现交互性不是特别好,比较好的方案是树形视图+右键选择操作,以后视情况完善。代码比较长,可能不够精简,好在基本是自己实现的(联动部分学习了Layui社区的做法):
<style>
#typeForm{
margin-top: 100px;
margin-left: 20px;
}
.inline-button{
width: 100px !important;
}
</style>
<form class="layui-form layui-form-pane" id="typeForm">
<div class="layui-form-item">
<label class="layui-form-label">请选择分类</label>
<div class="layui-input-inline">
<select name="category" id="category" lay-filter="category">
</select>
</div>
<div class="layui-input-inline ">
<select name="type" id="type" lay-filter="type">
</select>
</div>
<div class="layui-input-inline inline-button">
<button class="layui-btn layui-btn-s edit">编辑</button>
</div>
<div class="layui-input-inline inline-button">
<button class="layui-btn layui-btn-s layui-btn-danger delete">删除</button>
</div>
<div class="layui-input-inline inline-button">
<button class="layui-btn layui-btn-s create">新建</button>
</div>
</div>
</form>
<!-- 编辑分类弹框模版 -->
<script type="text/html" id="editPopup">
<form method="post">
<!-- 不能同时编辑一级分类和二级分类 -->
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">{{d.label}}</label>
<div class="layui-input-inline">
<input id="editType" autocomplete="off" class="layui-input" value="{{d.value}}" />
</div>
</div>
</div>
</form>
</script>
<!-- 新建分类弹框模版 -->
<script type="text/html" id="createPopup">
<form>
<!-- 不能同时新建一级分类和二级分类 -->
{{# if(d.category!=""){}}
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">一级分类</label>
<div class="layui-input-inline">
<input autocomplete="off" disabled="disabled" maxlength=10 class="layui-input" value="{{d.category}}" />
</div>
</div>
</div>
{{# } }}
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">{{d.label}}</label>
<div class="layui-input-inline">
<input id="createType" autocomplete="off" maxlength=10 class="layui-input" placeholder="{{d.label}}" />
</div>
</div>
</div>
</form>
</script>
<!-- 引入分类选择渲染js -->
<script type="text/javascript" src="/js/type_select.js"></script>
<script>
layui.use(['jquery','laytpl'], function() {
var $ = layui.jquery,
$form = $('#typeForm'),
laytpl = layui.laytpl;
//按钮事件监听
$(".edit").click(function () {
//如果未选择任何分类则直接返回
if(!categoryId){
layer.msg('请先选择分类', {icon: 2});
return false;
}
//弹出编辑框
var data={
"handle":editPopup, //模版视图id
//弹框标签和输入框值,根据是否选择二级分类(typeId是否为null)进行区别
"label":typeId?"二级分类":"一级分类",
"value":typeId?$form.find('select[name=type]').val():$form.find('select[name=category]').val()
};
open("编辑分类",data);
return false;
})
$(".delete").click(function () {
//如果未选择任何分类则直接返回
if(!categoryId){
layer.msg('请先选择分类', {icon: 2});
return false;
}
var warning;
//根据是否选择二级分类判断删除的是一级分类还是二级分类
if(typeId){
warning="确定要删除该二级分类吗?该二级分类下的所有文章将会被删除。";
}else{
warning="确定要删除该一级分类吗?该一级分类及其下属的二级分类下的所有文章将会被删除。";
}
layer.confirm(warning,{icon: 3, title:'提示'}, function(index){
$.ajax({
url: ""+(typeId?typeId:categoryId),
type: "DELETE",
data:JSON.stringify({
"userId":1
}),
contentType: "application/json; charset=utf-8",
success: function (result) {
layer.msg('删除分类成功', {icon: 1});
layer.close(index);
//重新初始化分类选项
init();
},
error:function(result){
layer.msg(result.responseText, {icon: 2});
}
});
});
return false;
})
$(".create").click(function () {
//弹出编辑框
var data={
"handle":createPopup, //模版视图id
//弹框标签和输入框值,根据是否选择一级分类进行区别
"label":categoryId?"二级分类":"一级分类",
"category":$form.find('select[name=category]').val()
};
open("新建分类",data);
return false;
})
//打开编辑框
function open(title,data) {
//渲染模版视图
var view = data.handle.innerHTML;
laytpl(view).render(data,function(html){
view=html;
});
layer.open({
type: 1 , //Page层类型,
btn:['确认'], //按钮
btnAlign: 'c',//按钮居中排列
title: title,
skin: 'layui-layer-prompt',
shade: 0.6, //遮罩透明度
maxmin: true, //允许全屏最小化
anim: 5 , //0-6的动画形式,-1不开启
content:view,
//确认按钮的回调函数
yes: function(index, layero){
//编辑分类处理
if(data.handle==editPopup){
//编辑之前的类名,根据是否选择二级分类判断在编辑哪一级分类
var before=typeId?$form.find('select[name=type]').val():$form.find('select[name=category]').val();
//如果未进行编辑则直接关闭弹框
if($("#editType").val()==before){
layer.close(index);
//判断类名是否为空
}else if(!$("#editType").val()){
layer.tips('类名不能未空', '#editType', {
tips: 2
});
//ajax提交数据
}else{
$.ajax({
url: "",
type: "PUT",
data:JSON.stringify({
"id":typeId?typeId:categoryId,
"typeName":$("#editType").val(),
"userId":1
}),
contentType: "application/json; charset=utf-8",
success: function (result) {
layer.msg('编辑分类成功', {icon: 1});
layer.close(index);
//重新初始化分类选项
init();
},
error:function(result){
layer.msg(result.responseText, {icon: 2});
}
});
}
//新建分类处理
}else{
if(!$("#createType").val()){
layer.tips('类名不能未空', '#createType', {
tips: 2
});
//ajax提交数据
}else {
$.ajax({
url: "",
type: "POST",
data:JSON.stringify({
"parentId": categoryId?categoryId:0,
"typeName": $("#createType").val(),
"userId":1
}),
contentType: "application/json; charset=utf-8",
success: function (result) {
layer.msg('新建分类成功', {icon: 1});
layer.close(index);
//重新初始化分类选项
init();
},
error:function(result){
layer.msg(result.responseText, {icon: 2});
}
});
}
}
}
});
}
});
</script>
分类选择表格的js代码在其他地方还会用到,为了复用将这部分代码放在单独的js文件(type_select.js)里面:
var categoryId;
var typeId;
var typeData;
//选项渲染
function appendOption($o,text,value){
//新建一个option
var $opt=layui.jquery("<option>").text(text).val(value);
$opt.appendTo($o);
}
layui.use(['jquery', 'form'], function() {
var $ = layui.jquery,
form = layui.form,
$form = $('#typeForm');
//绑定选择事件
form.on('select(category)', function(data) {
categoryEvent(data);
});
form.on('select(type)', function(data) {
typeEvent(data);
});
//监听一级分类选择事件
function categoryEvent(data){
//二级分类和typeID置空并添加提示选项
$('#type').html("");
typeId=null;
appendOption($('#type'),"二级分类","");
//当选择的不是提示选项时则遍历一级分类
if(data.value!=""){
$.each(typeData,function(index,category){
//如果是当前选择的一级分类且子分类非空则遍历二级分类
if(category.text==data.value && category.children){
//修改全局变量categoryID
categoryId=category.id;
$.each(category.children,function(index,type){
appendOption($('#type'),type.text,type.text);
});
}
});
//否则置空categoryId
}else{
categoryId=null;
}
//渲染表格
form.render();
}
//监听二级分类选择事件
function typeEvent(data){
//当选择的不是提示选项时则遍历一级分类
if(data.value!=""){
$.each(typeData,function(index,category){
//如果是当前选择的一级分类则遍历二级分类
if(category.id==categoryId) {
$.each(category.children,function(index,type){
//如果是当前选择的二级分类则修改全局变量typeId
if(type.text==data.value){
typeId=type.id;
}
});
}
});
//否则置空typeId
}else{
typeId=null;
}
}
});
//初始化一级分类
function initCategoty(categoryId,typeId) {
//清空当前数据
layui.jquery("#category").empty();
layui.jquery("#type").empty();
categoryId=categoryId;
typeId=typeId;
//请求数据
layui.jquery.ajax({
url: "/type?userId="+1,
type: "get",
dataType: "json",
success: function (result) {
typeData = result;
// 添加提示选项
appendOption(layui.jquery('#category'),"一级分类","");
appendOption(layui.jquery('#type'),"二级分类","");
// 遍历数据添加节点
layui.jquery.each(typeData,function(index,category){
appendOption(layui.jquery('#category'),category.text,category.text);
//根据传入的分类id改变默认选择的分类值
if(categoryId &&category.id==categoryId){
//模拟点击事件
layui.jquery('#category').next().find('.layui-select-title input').click();
setTimeout(function () {
layui.jquery('#category').next().find('.layui-anim').children('dd[lay-value="'+category.text+'"]').click();
},10);
layui.jquery.each(category.children,function(index,type){
//如果是当前选择的二级分类则修改
if(typeId&&type.id==typeId){
//模拟点击事件
layui.jquery('#type').next().find('.layui-select-title input').click();
setTimeout(function () {
layui.jquery('#type').next().find('.layui-anim').children('dd[lay-value="'+type.text+'"]').click();
},10);
}
});
}
});
layui.form.render();
}
});
}
接着也是在js文件夹下面新建一个json文件放入测试数据,格式如下:
[{
"id":1,
"text":"Java",
"children":[
{
"id":2,
"text":"JavaSE",
"children":[]
}]
}
]
最后就是新建文章页面了,主要是一个富文本编辑器。layui提供的富文本编辑器功能较少,所以我选择了比较成熟的百度UEditor:UEditor-首页。与SpringMVC的整合参考这一篇文章就可以:springmvc学习笔记--ueditor和springmvc的集成,写得非常详细。下载时注意下载源码版本,因为源码里有些地方需要修改。页面源码如下:
<style>
#typeForm{
margin-top: 20px;
margin-left: 20px;
position:relative;
z-index: 1;
}
#typeForm #title{
width:700px;
}
.inline-button-div{
margin-left: 20px;
width:300px;
}
.inline-button{
width:100px !important;
}
#container{
z-index: -1;
position: inherit;
margin-left: 320px;
margin-top: -40px;
height: 360px;
width:1000px;
}
</style>
<form class="layui-form layui-form-pane" id="typeForm">
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-inline">
<select name="category" id="category" lay-filter="category">
</select>
</div>
<div class="layui-input-inline ">
<select name="type" id="type" lay-filter="type">
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-inline">
<input id="title" class="layui-input" maxlength="50" placeholder="请输入标题" />
</div>
</div>
</form>
<div class="inline-button-div">
<div class="layui-input-inline inline-button">
<button id="publish" class="layui-btn" lay-filter="submit">发表博客</button>
</div>
<div class="layui-input-inline inline-button">
<button id="draft" class="layui-btn" lay-filter="submit">保存草稿</button>
</div>
</div>
<!-- 引入分类选择渲染js -->
<script type="text/javascript" src="/js/type_select.js"></script>
<script src="/ueditor/ueditor.config.js"></script>
<script src="/ueditor/ueditor.all.min.js"></script>
<script src="/ueditor/lang/zh-cn/zh-cn.js"></script>
<script id="container" name="content" type="text/plain" ></script>
<script type="text/javascript">
layui.use(['jquery', 'form'], function() {
var $ = layui.jquery,
form = layui.form,
$form = $('#typeForm'),
ue = UE.getEditor('container'),
createTime;
//富文本编辑器初始化
ue.ready(function() {
$.ajax({
url: "/getTime",
data:"format=yyyy年 MM月 dd日 HH:mm:ss",
type: "get",
success: function (result) {
createTime=result;
ue.setContent("<p>写下文字,记录生活</p><p>创建于:"+result+"</p>");
}
});
ue.addListener('focus',function(){
if(/^写下文字,记录生活创建于:\d{4}年\s\d{2}月\s\d{2}日\s\d{2}:\d{2}:\d{2}$/.test(ue.getContentTxt())){
ue.setContent("<p></p><p>创建于:"+createTime+"</p>");
ue.focus(false);
}
})
window.onbeforeunload=function(e){
if(!/^写下文字,记录生活创建于:\d{4}年\s\d{2}月\s\d{2}日\s\d{2}:\d{2}:\d{2}$/.test(ue.getContentTxt())) {
return (e || window.event).returnValue = '内容可能尚未保存,确定离开吗';
}
}
});
});
</script>
呈现的效果:
至此后台管理系统的页面部分就基本完成了。接下来是后台管理系统的后端开发。