分享一下最近花了2天时间来做的一个layui前端的CURD,先来看看效果是不是自己想要的吧... 【代码放最后了】
因为每天还要上课,所以虽然花了2天时间来弄,但实际上写的时间比较少,有些功能做的不是很好,还请大佬见谅
可参考layui官方开发文档:https://www.layui.com/doc/
以及在线示例:https://www.layui.com/demo/
layui前端页面数据展示:已解决数据格式化问题
添加 :有验证
修改:已做数据回显
删除:有单独点击一个删除以及批量删除
高级查询:
以及一些扩展小功能
【代码部分】
JSP页面
温馨小提示:引入的js,css等可根据自己的文件位置修改。
注意 :
①layui的资源文件建议是从官网下载的最新版本 https://www.layui.com/ ,在这里因为我用的基于layui的X-admin框架去搭建的前端,而框架里面的layui样式不是最新版,导致期间出现一些功能不能实现,真的很坑人...
②前端数据表格的展示注意后端返回的json数据格式建议必须如下 code,msg,count,data code返回的值不能为空,data里面装页面显示数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 此部分代码做如果项目配置运行时有path的时候使用 --%>
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
System.out.println(basePath);
%>
<html>
<head>
<base href="<%=basePath%>"/>
<title>菜单管理</title>
<%@ include file="/WEB-INF/views/head.jsp"%>
<%@ include file="/WEB-INF/views/common.jsp"%>
<script type="text/javascript" src="/static/js/common.js"></script>
<script type="text/javascript" src="/static/js/model/menu.js"></script>
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body class="layui-anim layui-anim-up">
<div class="x-nav">
<span class="layui-breadcrumb">
<a href="/main">首页</a>
<a href="/main">系统管理</a>
<a><cite>菜单管理</cite></a>
</span>
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" href="javascript:location.replace(location.href);" title="刷新">
<i class="layui-icon" style="line-height:30px">ဂ</i></a>
</div>
<div class="x-body">
<%--<div class="layui-row">
<form class="layui-form layui-col-md12 x-so">
<input class="layui-input" placeholder="开始日" name="start" id="start">
<input class="layui-input" placeholder="截止日" name="end" id="end">
<input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input">
<button class="layui-btn" lay-submit="" lay-filter="sreach"><i class="layui-icon"></i></button>
</form>
</div>--%>
<div class="layui-row">
<form class="layui-form layui-col-md12 x-so" id="zq_search">
菜单:<input id="name" type="text" name="name" placeholder="请输入菜单" autocomplete="off" class="layui-input">
<button id="search" class="layui-btn" lay-submit="" lay-filter="search"><i class="layui-icon"></i></button>
</form>
</div>
<table class="layui-hide" id="zq_table" lay-filter="zq_table"></table>
</div>
<div class="layui-row" id="zq_formpopbox" style="display:none;position: absolute;
top: 0; left: 0; bottom: 0; right: 0;">
<div class="layui-col-md11">
<form id="zq_form" class="layui-form" action="" style="margin-top: 20px;align:center;">
<%--隐藏字段id,区分添加和修改--%>
<input type="hidden" name="id"/>
<%--lay-verify验证的值:
required(必填项),phone(手机号),email(邮箱)
url(网址),number(数字),date(日期),identity(身份证)
自定义值--%>
<div class="layui-form-item">
<label class="layui-form-label">菜单名称</label>
<div class="layui-input-block">
<input type="text" name="name" id="name" lay-verify="required" placeholder="请输入菜单名称" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单路径</label>
<div class="layui-input-block">
<input type="text" name="url" id="url" lay-verify="" placeholder="请输入菜单路径" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单图标</label>
<div class="layui-input-block">
<input type="text" name="icon" lay-verify="" placeholder="请输入菜单图标" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单</label>
<div class="layui-input-block">
<input type="text" name="parent" lay-verify="" placeholder="请输入菜单" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">子菜单</label>
<div class="layui-input-block">
<input type="text" name="children" lay-verify="" placeholder="请输入子菜单" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-radius layui-btn-normal" lay-submit="" lay-filter="zq_submit" <%--onclick="zq_submit()"--%>>确认</button>
<%--<input type="button" class="layui-btn layui-btn-radius layui-btn-normal" value="确认" onclick="zq_submit()" />--%>
<button type="reset" class="layui-btn layui-btn-radius layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
</div>
<%-- 解决对象格式化问题
注意:{{d.id}} 是动态内容,它对应数据接口返回的字段名。除此之外,你还可以读取到以下额外字段:
序号:{{ d.LAY_INDEX }} (该额外字段为 layui 2.2.0 新增)--%>
<script type="text/html" id="zq_formatter">
{{# if( d.parent != null){ }}
{{d.parent.name}}
{{# } }}
</script>
<%-- 这里放头工具栏按钮 id和table头的toolbar属性绑定--%>
<script type="text/html" id="zq_toolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-danger layui-btn-sm" lay-event="delAll"><i class="layui-icon"></i>批量删除</button>
<button class="layui-btn layui-btn-sm" lay-event="add" <%--onclick=""--%>><i class="layui-icon"></i>添加</button>
</div>
</script>
<%-- 这里放CRUD行工具栏按钮 id和table行的toolbar属性绑定--%>
<script type="text/html" id="zq_bar">
<a <%--class="layui-btn layui-btn-primary layui-btn-xs"--%> lay-event="detail" title="查看"><i class="layui-icon"></i></a>
<a <%--class="layui-btn layui-btn-xs"--%> lay-event="edit" title="编辑"><i class="layui-icon"></i></a>
<a <%--class="layui-btn layui-btn-danger layui-btn-xs"--%> lay-event="del" title="删除"><i class="layui-icon"></i></a>
</script>
<!--_footer 作为公共模版分离出去-->
<%@ include file="/WEB-INF/views/footer.jsp"%>
</body>
</html>
这里放一个抽取出来的公共 common.js
//序列化form表单字段为json对象格式
$.fn.serializeFormToJson = function(){
var arr = $(this).serializeArray();//form表单数据 name:value
var param = {};
$.each(arr,function(i,obj){ //将form表单数据封装成json对象
param[obj.name] = obj.value;
})
return param;
}
/**
* 注意:这里使用了上面的方式,没有使用这种-------------------------------------------
* 将form里面的内容序列化成json
* 相同的checkbox用分号拼接起来
* @param {dom} 指定的选择器
* @param {obj} 需要拼接在后面的json对象
* @method serializeJson
* */
$.fn.serializeJson=function(otherString){
var serializeObj={},
array=this.serializeArray();
$(array).each(function(){
if(serializeObj[this.name]){
serializeObj[this.name]+=';'+this.value;
}else{
serializeObj[this.name]=this.value;
}
});
if(otherString!=undefined){
var otherArray = otherString.split(';');
$(otherArray).each(function(){
var otherSplitArray = this.split(':');
serializeObj[otherSplitArray[0]]=otherSplitArray[1];
});
}
return serializeObj;
};
/**
* 将josn对象赋值给form
* @param {dom} 指定的选择器
* @param {obj} 需要给form赋值的json对象
* @method serializeJson
* */
$.fn.setForm = function(jsonValue){
var obj = this;
$.each(jsonValue,function(name,ival){
var $oinput = obj.find("input[name="+name+"]");
if($oinput.attr("type")=="checkbox"){
if(ival !== null){
var checkboxObj = $("[name="+name+"]");
var checkArray = ival.split(";");
for(var i=0;i<checkboxObj.length;i++){
for(var j=0;j<checkArray.length;j++){
if(checkboxObj[i].value == checkArray[j]){
checkboxObj[i].click();
}
}
}
}
}
else if($oinput.attr("type")=="radio"){
$oinput.each(function(){
var radioObj = $("[name="+name+"]");
for(var i=0;i<radioObj.length;i++){
if(radioObj[i].value == ival){
radioObj[i].click();
}
}
});
}
else if($oinput.attr("type")=="textarea"){
obj.find("[name="+name+"]").html(ival);
}
else{
obj.find("[name="+name+"]").val(ival);
}
})
}
JSP页面对应所需js代码
$(function () {
layui.config({
version: '1545041465480' //为了更新 js 缓存,可忽略
});
//注意:这里是数据表格的加载数据,必须写
layui.use(['table', 'layer', 'form', 'laypage', 'laydate'], function () {
var table = layui.table //表格
,layer = layui.layer //弹层
,form = layui.form //form表单
,laypage = layui.laypage //分页
,laydate = layui.laydate;//日期
//执行一个laydate实例
laydate.render({
elem: '#start' //指定元素
});
//执行一个laydate实例
laydate.render({
elem: '#end' //指定元素
});
//执行一个 table 实例
table.render({
elem: '#zq_table'
,id: 'tableReload'//重载数据表格
,url: '/menu/page' //数据接口
,toolbar: '#zq_toolbar' //开启头工具栏,此处default:显示默认图标,可以自定义模板,详见文档
,title: 'xx表'
,page: true //开启分页
// ,totalRow: true //开启合计行
,cols: [[ //表头
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合计:'} //totalRow:true则代表这列数据要合计
,{field: 'name', title: '菜单名称',edit: 'text'}
,{field: 'url', title: '菜单路径', sort: true, totalRow: true,edit: 'text'}
,{field: 'icon', title: '菜单图标', sort: true,edit: 'text'}
,{field: 'parent', title: '菜单', sort: true, totalRow: true,edit: 'text',templet: '#zq_formatter'}
,{field: 'children', title: '子菜单',edit: 'text'}
,{fixed: 'right', width: 165, align:'center', toolbar: '#zq_bar'}
]]
});
//监听头工具栏事件
table.on('toolbar(zq_table)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //获取选中的数据
//json字符串转换成Json数据 eval("("+jsonStr+")") /JSON.parse(jsonStr)
data = eval("("+JSON.stringify(data)+")");
switch(obj.event){
case 'delAll':
if(data.length === 0){
layer.msg('请至少选择1行', { icon: 2, time: 1500 });
}else {
layer.alert('您确认要删除'+data.length+'条数据吗?', {
skin: 'layui-layer-molv' //样式类名layui-layer-lan或layui-layer-molv 自定义样式
,closeBtn: 1 // 是否显示关闭按钮
,anim: 1 //动画类型
,btn: ['确定','取消'] //按钮
,icon: 2 // icon
,yes:function(){
// layer.msg('确定', { icon: 1, time: 1500 });
for (var i=0;i<data.length;i++){
console.debug("id:======"+data[i].id)
//发送请求到后台
$.post("menu/delete", { id: data[i].id }, function (result) {
if (result.code == "1") {//删除成功,刷新当前页表格
// obj.del(); //删除对应行(tr)的DOM结构,并更新缓存
layer.msg(result.msg, { icon: 1, time: 1500 });
// layer.close(index);
$(".layui-laypage-btn").click();//点击分页刷新当前页
}else if(result.code == "-1"){ //删除失败
layer.alert(result.msg, { icon: 2},function () {
$(".layui-laypage-btn").click();
window.location.reload();
});
}
});
}
/* //捉到所有被选中的,发异步进行删除
layer.msg('删除成功', {icon: 1});
$(".layui-form-checked").not('.header').parents('tr').remove();*/
}
,btn2:function(){
layer.msg('好的,暂时不给您删除。',{ icon: 1, time: 1500 });
}
});
}
break;
case 'add':
zq_form('添加菜单','url这个值不管','','');
//数据回显
// $("#zq_form").setForm({id:data.id,name: data.name, url: data.url,icon:data.icon,parent:data.parent,children:data.children});
$("#zq_form").setForm({id:''});
break;
}
});
//监听行工具事件
table.on('tool(zq_table)', function(obj){ //注:tool 是工具条事件名,zq_table 是 table 原始容器的属性 lay-filter="对应的值"
var data = obj.data //获得当前行数据
,layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
var tr = obj.tr; //获得当前行 tr 的DOM对象
switch(layEvent){
case 'detail':
//json字符串转换成Json数据 eval("("+jsonStr+")") /JSON.parse(jsonStr)
var jsonstr = JSON.stringify(data);//json数据转字符串 JSON.stringify(obj)
layer.alert(jsonstr);
break;
case 'del':
layer.confirm('您确定删除id:'+data.id+'的数据吗?', function(index){
//向服务端发送删除指令,在这里可以使用Ajax异步
$.post("menu/delete", { id: data.id }, function (ret) {
if (ret.code == "1") {//删除成功,刷新当前页表格
layer.msg(ret.msg, { icon: 1, time: 1500 }, function () {
obj.del(); //删除对应行(tr)的DOM结构,并更新缓存
layer.close(index);
// $(".layui-laypage-btn").click();//点击分页刷新当前页
});
}else if(ret.code == "-1"){ //删除失败
layer.alert(ret.msg, { icon: 2},function () {
layer.close(index);
// $(".layui-laypage-btn").click();
window.location.reload();
});
}
});
});
break;
case 'edit':
console.debug(data);
zq_form('编辑菜单','url这个值不管',500,400);
//数据回显
$("#zq_form").setForm({id:data.id,name: data.name, url: data.url,icon:data.icon,parent:data.parent,children:data.children});
break;
}
});
//监听单元格编辑 zq_table 对应 <table> 中的 lay-filter="zq_table" 做可编辑表格使用
table.on('edit(zq_table)', function(obj){
var value = obj.value //得到修改后的值
,data = obj.data //得到所在行所有键值
,field = obj.field; //得到字段
layer.msg('[ID: '+ data.id +'] ' + field + ' 字段更改为:'+ value);
});
/*
//监听显示操作
form.on('switch(isShow)', function(obj) {
var t = this;
layer.tips(t.value + ' ' + t.name + ':' + obj.elem.checked, obj.othis);
});*/
//监听提交 lay-filter="zq_submit"
form.on('submit(zq_submit)', function(data){
// console.log(data.elem) //被执行事件的元素DOM对象,一般为button对象
// console.log(data.form) //被执行提交的form对象,一般在存在form标签时才会返回
console.log(data.field) //当前from表单所提交的所有字段, 名值对形式:{name: value}
layer.msg(JSON.stringify(data.field));//表格数据序列化
var formData = data.field;
var id = formData.id,
name = formData.name,
url=formData.url,
icon=formData.icon,
parent_id=formData.parent_id;
$.ajax({
type: "post", //数据提交方式(post/get)
url: "/menu/save", //提交到的url
data: {"id":id,"name":name,"url":url,"icon":icon,"parent_id":parent_id},//提交的数据
dataType: "json",//返回的数据类型格式
success: function(msg){
if (msg.success){ //成功
layer.msg(msg.msg, { icon: 1, time: 1500 });
table.reload('tableReload');//数据表格重载
layer.close(index);//关闭弹出层
}else { //失败
layer.alert(msg.msg, { icon: 2},function () {
// $(".layui-laypage-btn").click();//执行分页刷新当前页
layer.close(index);
// window.location.reload();
});
}
}
});
return false;//false:阻止表单跳转 true:表单跳转
});
//监听提交 lay-filter="search"
form.on('submit(search)', function(data){
layer.msg(JSON.stringify(data.field));//表格数据序列化
var formData = data.field;
console.debug(formData);
var name = formData.name,
url=formData.url,
icon=formData.icon,
parent_id=formData.parent_id;
//数据表格重载
table.reload('tableReload', {
page: {
curr: 1 //重新从第 1 页开始
}
, where: {//这里传参 向后台
name: name,
url:url
}
, url: '/menu/page'//后台做模糊搜索接口路径
, method: 'post'
});
return false;//false:阻止表单跳转 true:表单跳转
});
});
});
var index;//layer.open 打开窗口后的索引,通过layer.close(index)的方法可关闭
//表单弹出层
function zq_form(title,url,w,h){
if (title == null || title == '') { title=false; };
if (url == null || url == '') { };// url="404.html";
if (w == null || w == '') { w=($(window).width()*0.9); };
if (h == null || h == '') { h=($(window).height() - 50); };
index = layer.open({ //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
type:1,
title:title,
area: ['25%','55%'],//类型:String/Array,默认:'auto' 只有在宽高都定义的时候才不会自适应
// area: [w+'px', h +'px'],
fix: false, //不固定
maxmin: true,//开启最大化最小化按钮
shadeClose: true,//点击阴影处可关闭
shade:0.4,//背景灰度
skin: 'layui-layer-rim', //加上边框
content:$("#zq_formpopbox").html()
});
}
后端的代码我就不放了,根据自己的需要来吧