从简到繁——SSM个人博客搭建完全记录【2】后台管理系统页面设计——使用Layui

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/van_brilliant/article/details/79581307

前言

  搭建完生产环境,接下来进行后台管理系统页面的设计。目前自己的学习重点和知识领域主要还是在后端,但是前端有很多框架,或者说很多适合后端程序员使用的框架,比如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" οnclick="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.οnbefοreunlοad=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>

呈现的效果:  


至此后台管理系统的页面部分就基本完成了。接下来是后台管理系统的后端开发。

展开阅读全文

没有更多推荐了,返回首页