LayUI是现在比较流行的一款前端框架,数据表格也是后台管理中很长用到的工具了。
最近做项目就用到了,项目的要求是用数据表格显示出后台文章的列表并且每一行的文章都有对应的修改删除操作按钮。之后就写了一个小案例,做一下整理和记录。
首先需要引入LayUI的CSS和JS样式。
之后页面代码只需要一个table标签即可,只有用JS请求数据渲染表格。
<table class="layui-hide" id="student" lay-filter="student"></table>
JS加载数据,渲染表格(cols中的字段一定要和返回的JSON数据的键名一样)。
<script type="text/javascript">
layui.use(["table", "form"], function () {
var table = layui.table;
table.render({
elem: '#student',
title: '学生管理',
url: 'student/page',
height: 'full-210',
toolbar: true,
page: true,
cols: [ [
{type:'checkbox', fixed: 'left'},
{field: 'id', hide : true, title: 'id' },
{field: 'name', title: '姓名' },
{field: 'username', title: '用户名' }
] ]
});
});
</script>
其中render中可以设置表格的属性,LayUI数据表格支持的属性有,可以根据自己需求设置。
参数 | 类型 | 说明 | 示例值 |
---|---|---|---|
elem | String/DOM | 指定原始 table 容器的选择器或 DOM,方法渲染方式必填 | "#demo" |
cols | Array | 设置表头。值是一个二维数组。方法渲染方式必填 | |
url(等) | - | 异步数据接口相关参数。其中 url 参数为必填项 | |
toolbar | String/DOM/Boolean | 开启表格头部工具栏区域,该参数支持四种类型值:
注意: |
false |
defaultToolbar | Array | 该参数可自由配置头部工具栏右侧的图标按钮 | |
width | Number | 设定容器宽度。table容器的默认宽度是跟随它的父元素铺满,你也可以设定一个固定值,当容器中的内容超出了该宽度时,会自动出现横向滚动条。 | 1000 |
height | Number/String | 设定容器高度 | |
cellMinWidth | Number | (layui 2.2.1 新增)全局定义所有常规单元格的最小宽度(默认:60),一般用于列宽自动分配的情况。其优先级低于表头参数中的 minWidth | 100 |
done | Function | 数据渲染完的回调。你可以借此做一些其它的操作 | |
data | Array | 直接赋值数据。既适用于只展示一页数据,也非常适用于对一段已知数据进行多页展示。 | [{}, {}, {}, {}, …] |
totalRow | Boolean | 是否开启合计行区域。layui 2.4.0 新增 | false |
page | Boolean/Object | 开启分页(默认:false) 注:从 layui 2.2.0 开始,支持传入一个对象,里面可包含 laypage 组件所有支持的参数(jump、elem除外) | {theme: '#c00'} |
limit | Number | 每页显示的条数(默认:10)。值务必对应 limits 参数的选项。 注意:优先级低于 page 参数中的 limit 参数 |
30 |
limits | Array | 每页条数的选择项,默认:[10,20,30,40,50,60,70,80,90]。 注意:优先级低于 page 参数中的 limits 参数 |
[30,60,90] |
loading | Boolean | 是否显示加载条(默认:true)。如果设置 false,则在切换分页时,不会出现加载条。该参数只适用于 url 参数开启的方式 | false |
title | String | 定义 table 的大标题(在文件导出等地方会用到)layui 2.4.0 新增 | "用户表" |
text | Object | 自定义文本,如空数据时的异常提示等。注:layui 2.2.5 开始新增。 | |
autoSort | Boolean | 默认 true,即直接由 table 组件在前端自动处理排序。 若为 false,则需自主排序,通常由服务端直接返回排序好的数据。 注意:该参数为 layui 2.4.4 新增 |
|
initSort | Object | 初始排序状态。用于在数据表格渲染完毕时,默认按某个字段排序。 | |
id | String | 设定容器唯一 id。id 是对表格的数据操作方法上是必要的传递条件,它是表格容器的索引,你在下文诸多地方都将会见识它的存在。 值得注意的是:从 layui 2.2.0 开始,该参数也可以自动从 <table id="test"></table> 中的 id 参数中获取。 |
test |
skin(等) | - | 设定表格各种外观、尺寸等 |
其中URL地址为加载表格数据的请求,后端查询方法(持久层用的SpringDataJpa)。
@RequestMapping(value="/page")
@ResponseBody
public Object page(TablePageable pageParam) {
PageRequest pageable = pageParam.bulidPageRequest();
Page<Student> page=studentService.findAll(pageable);
return DataGridUtils.buildResult(page);
}
方法中接收参数的TablePageable类是接收数据表格的分页参数及方法,代码如下。
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
public class TablePageable{
private Integer limit; //分页
private String sort; //排序字段
private String order; //顺序,逆序
private Integer page; //分页
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public String getSort() {
return sort;
}
public void setSort(String sort) {
this.sort = sort;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
public PageRequest bulidPageRequest() {
int page=(this.page!=null)?this.page-1:0;
int size=limit!=null?limit:10;
if(sort==null) {
return PageRequest.of(page, size);
}else {
Order order2=new Order(Direction.fromString(order), sort);
Sort sort2=Sort.by(order2);
return PageRequest.of(page,size,sort2 );
}
}
public PageRequest bulidPageable(Sort sort) {
int page=(this.page!=null)?this.page-1:0;
int size=limit!=null?limit:10;
return PageRequest.of(page, size, sort);
}
public Sort bulidSort() {
Order order2=new Order(Direction.fromString(order), sort);
Sort sort2=Sort.by(order2);
return sort2;
}
}
返回的DataGridUtils类中的方法是处理返回的数据为指定的JSON格式数据。
指定的JSON格式为。
DataGridUtils类代码如下。
public class DataGridUtils {
public static HashMap<String, Object> buildResult(Page page) {
HashMap<String, Object> result=new HashMap<>();
result.put("code", 0);
result.put("msg","");
result.put("number", page.getNumberOfElements());
result.put("count", page.getTotalElements());
result.put("data", page.getContent());
return result;
}
}
返回的JSON数据(只有返回的JSON数据格式一样数据就可以显示出来了)。
{
"msg": "",
"number": 3,
"code": 0,
"data": [
{
"id": 2,
"isUsed": true,
"name": "张三",
"username": "123456",
"tbClass": {
"id": 1,
"name": "软件工程1班",
"teacher": "张老师"
},
"grade": 99.0
}, {
"id": 3,
"isUsed": null,
"name": "刘备",
"username": "admin",
"tbClass": {
"id": 1,
"name": "软件工程1班",
"teacher": "张老师"
},
"grade": null
}, {
"id": 4,
"isUsed": null,
"name": "诸葛亮",
"username": "admin1",
"tbClass": {
"id": 2,
"name": "软件工程2班",
"teacher": "李老师"
},
"grade": null
}
],
"count": 3
}
数据返回后,就可以看到页面上显示的页面了。
上面是显示的单表数据,在实际开发中,常遇到关联表的数据显示。用以下方法可以显示关联表数据。
{field : 'tbClass', title : '班级',
templet : function(d) { //d表格当前行的所有数据,如果班级对象不为空,就返回班级名称
return d.tbClass ? d.tbClass.name : '';
}
},
数据显示完成后,下一步就是对数据的操作了(增删改查)。LayUI数据表格支持在表格上方自定义工具栏,也可以在每行后面定义操作按钮,先来看一下在表格上方定义工具栏。
定义增删改查工具栏代码。
注意:需要用script表格包裹起来,id用于绑定时使用,按钮上的lay-event属性用于监听按钮的操作。
<script type="text/html" id="toolbarDemo">
<div class="layui-btn-group">
<button class="layui-btn layui-btn-sm" lay-event="add"><i class="layui-icon"></i>新增</button>
<button class="layui-btn layui-btn-sm" lay-event="updata"><i class="layui-icon"></i>修改</button>
<button class="layui-btn layui-btn-sm" lay-event="delete"><i class="layui-icon"></i>删除</button>
<button class="layui-btn layui-btn-sm" lay-event="refresh"><i class="layui-icon"></i>刷新</button>
</div>
</script>
之后在JS渲染代码中,通过toolbar属性绑定自定义的工具栏。
工具栏加载完成,页面显示。
工具栏添加后,可以通过以下方法,监听工具栏的点击事件,test为表格的id。
table.on('toolbar(test)', function(obj){});
点击工具栏按钮,在控制台输出obj,可以发现,event的值,正是工具栏按钮中lay-event属性的值,可以通过他来判断点击的是哪个按钮,执行什么操作。
可以通过下面的代码获取到选中的数据,进行操作(删除修改)。
var checkStatus = table.checkStatus('student');
var data = checkStatus.data;
点击新增按钮方法,打开一个layer弹框,显示新增表单,先请求后台拿到新增页面代码,之后弹框显示。弹框定义了两个按钮,确定取消,点击确定按钮会提交表单内容到后台进行保存操作。
$.post("student/edit", function(data){
layui.use('layer', function(){
layer.open({
title: '学生管理',
type: 1,
shade: 0.3,
maxmin: true,
content: data,
area: ['500px'],
btn: ['确定', '取消'],
yes:function(){ //虚拟化表单参数类型不是json,所以这里用的是回调提交
},
//弹出层打开回调
success: function(layero, index){
var form=layui.form;
//找到确定按钮,添加属性,变成提交按钮
layero.addClass('layui-form');
var submitBtn=layero.find('.layui-layer-btn0');
submitBtn.attr('lay-filter','formVerify').attr('lay-submit','');
layero.keydown(function(e){
if(e.keyCode==13){
submitBtn.click();
}
});
form.on('submit(formVerify)', function(data){
$.post("student/save", data.field, function(result){
if(result.success){
layer.close(index);
table.reload('student',{where:that.where});
}
layer.msg(result.msg,{offset:'rb'});
});
});
}
})
})
})
后台edit方法,请求新增修改页面代码,因为关联的有班级,所以把所有的班级查询出来传递到前台。新增和修改公用的一个方法和页面,用id作为区分的。
@Override
public void edit(StudentForm form, ModelMap map) throws InstantiationException, IllegalAccessException {
map.put("tbClass", tbClassService.findAll());
Student model = new Student();
Integer id = form.getId();
if(id!=null) {
model=studentService.findById(id);
}
map.put("model", model);
}
edit页面代码,model为传递过来的对象,如果是新增就为null,修改就显示修改的值。
<style type="text/css">
.myData .layui-form-item{
margin: 20px 100px 10px 45px;
}
.myData .layui-form-label{
width: 80px;
}
</style>
<form class="layui-form myData" action="save" method="post" lay-filter="stuform">
<input type="hidden" name="id" data-th-value="${model.id}" />
<input type="hidden" name="isUsed" data-th-value="${model.isUsed}" />
<input type="hidden" name="grade" data-th-value="${model.grade}" />
<div class="layui-form-item" >
<label class="layui-form-label">班级名称:</label>
<div class="layui-input-block">
<select name="tbClass.id">
<option></option>
<option data-th-each="t:${tbClass}" data-th-value="${t.id}" data-th-selected="${model.tbClass==null? null: model.tbClass.id == t.id}" data-th-text="${t.name}">班级名称</option>
</select>
</div>
</div>
<div class="layui-form-item" >
<label class="layui-form-label">姓名:</label>
<div class="layui-input-block">
<input type="text" name="name" lay-verify="required" th:value="${model.name}" 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="username" lay-verify="required" th:value="${model.username}" class="layui-input" />
</div>
</div>
</form>
<script>
layui.use("form", function () {
var form = layui.form;
form.render('select');
});
</script>
后台保存方法。
@RequestMapping(value="/save")
@ResponseBody
public Object save(StudentForm form) throws InstantiationException, IllegalAccessException {
try {
Student model=new Student();
Integer id = form.getId();
if(id!=null) {
model=studentService.findById(id);
}
BeanUtils.copyProperties(form, model,"id");
studentService.save(model);
return new AjaxResult("数据保存成功");
} catch (Exception e) {
return new AjaxResult(false,"数据保存失败");
}
}
其中接收参数的StudentForm类中和实体类字段一样,通过id是否为null来判断是修改还是新增。AjaxResult是方法执行完成后,返回前台的一个类代码如下。
public class AjaxResult {
private Boolean success;
private String msg;
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public AjaxResult(String msg) {
super();
this.success=true;
this.msg = msg;
}
public AjaxResult(Boolean success, String msg) {
super();
this.success = success;
this.msg = msg;
}
public AjaxResult(boolean success) {
this.success=success;
}
@SuppressWarnings("rawtypes")
public static HashMap<String, Object> bulidPageResult(Page page) {
HashMap<String, Object> result=new HashMap<>();
result.put("total", page.getTotalElements());
result.put("rows", page.getContent());
return result;
}
}
效果如下。
修改部分JS代码,修改需要先判断一下是否勾选了,勾选一行才能执行修改操作。
if(data.length != 1){
layer.msg('请选择一行进行编辑', {offset: 'rb'});
}else{
var id = data[0].id;
$.post("student/edit", {id: id}, function(data){
layui.use('layer', function(){
layer.open({
title: '学生管理',
type: 1,
shade: 0.3,
maxmin: true,
content: data,
area: ['500px'],
btn: ['确定', '取消'],
yes:function(){
},
success: function(layero, index){
var form=layui.form;
layero.addClass('layui-form');
var submitBtn=layero.find('.layui-layer-btn0');
submitBtn.attr('lay-filter','formVerify').attr('lay-submit','');
layero.keydown(function(e){
if(e.keyCode==13){
submitBtn.click();
}
});
form.on('submit(formVerify)', function(data){
$.post("student/save", data.field, function(result){
if(result.success){
layer.close(index);
table.reload('student',{where:that.where});
}
layer.msg(result.msg,{offset:'rb'});
});
});
}
})
})
});
}
因为修改和新增都是公用的一个方法,所以后台,页面都和新增的方法一样,下面看一下效果图。
删除方法,JS部分代码,删除相对来说就简单很多了,只需要把选中的行id拼接起来,传递到后台进行删除就可以了。
if(data.length < 1){
layer.msg('请选择需要删除的行', {offset: 'rb'});
}else{
layer.confirm('确定要删除选中的'+data.length+'条数据吗?', function(index) {
var str = "";
for(i = 0; i < data.length; i++){
str += data[i].id+",";
}
str = str.substring(0, str.length-1);
$.post("student/delete1", {ids: str}, function(result){
table.reload('student',{where:that.where});
layer.close(index);
layer.msg(result.msg,{offset:'rb'});
});
});
}
后台删除方法。
@RequestMapping(value = "delete1")
@ResponseBody
public Object delete(String ids) {
try {
String[] split = ids.split(",");
for(int i = 0; i < split.length; i++) {
studentService.deleteById(Integer.parseInt(split[i]));
}
return new AjaxResult("数据删除成功");
} catch (Exception e) {
return new AjaxResult(false,"数据删除失败");
}
}
最后就是刷新方法了,刷新也是最简单的。只有执行table.reload('student', {where:that.where});方法,刷新表格,重新加载一下数据就可以了。
增删改查,就差一个查询了查询方法你可以同上面新增和修改方法一样用一个弹框显示查询条件也可以,也可以在表格上方定义查询表单,这里案例是在表格上方定义的查询表单。
在表格上方加上下面的代码,查询表单。
<form class="layui-form" action="save" id="myForm" method="post" lay-filter="stuform">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">班级:</label>
<div class="layui-input-inline">
<input type="text" name="teahcerName" class="layui-input" />
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">姓名:</label>
<div class="layui-input-inline">
<input type="text" name="name" class="layui-input" />
</div>
</div>
<div class="layui-inline">
<button type="button" class="layui-btn layui-btn-radius layui-btn-normal" onclick="search()">
<i class="layui-icon"></i>查询
</button>
<button type="button" class="layui-btn layui-btn-radius layui-btn-normal" onclick="empty()">
<i class="layui-icon"></i>清空
</button>
</div>
</div>
</form>
效果如下。
查询方法,查询只需要把查询条件带上,之后刷新表格,后台加载表格数据时,判断查询条件是否为null,不为null就条件查询数据返回即可。查询条件放在where变量中,刷新表格时带上where参数即可。
$.fn.serializeObject = function(){ //序列化表单数据
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
function search(){
layui.use("table", function(){
var table = layui.table;
where = $("#myForm").serializeObject();
table.reload('student', {where: where});
});
}
清空查询方法,把查询条件where清空,不带参数刷新表格就是全部数据了,之后还需要把查询表单的数据清空一下。
function empty(){
where="";
$("input").val("");
layui.use(['form', 'table'], function(){
var form = layui.form;
var table = layui.table;
form.render();
table.reload('student', {where: ''});
});
}
增删改查基本都实现了。但操作按钮都是是表格上方工具栏中,下面来看一下在表格中定义操作按钮。
和在表格上面工具栏中定义一样,需要先定义显示在表格中的操作按钮。
注意:需要用script表格包裹起来,id用于绑定时使用,按钮上的lay-event属性用于监听按钮的操作。
<script type="text/html" id="barDemo">
<button class="layui-btn layui-btn-xs" lay-event="updata"><i class="layui-icon"></i>修改</button>
<button class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete"><i class="layui-icon"></i>删除</button>
</script>
在JS渲染表格时,添加操作列,通过id绑定操作代码块。
{field: 'relationName', toolbar: '#barDemo', title: '操作' }
页面显示效果如图。
通过table.on('tool(student)', function(obj) {});方法监听表格内工具栏的点击事件。
通过var data = obj.data;获取当前行的数据。
JS部分代码。
table.on('tool(student)', function(obj) {
var data = obj.data;
if (obj.event === 'updata') {
$.post("student/edit", {id: data.id}, function(data){
layui.use('layer', function(){
layer.open({
title: '学生管理',
type: 1,
shade: 0.3,
maxmin: true,
content: data,
area: ['500px'],
btn: ['确定', '取消'],
yes:function(){
},
success: function(layero, index){
var form=layui.form;
layero.addClass('layui-form');
var submitBtn=layero.find('.layui-layer-btn0');
submitBtn.attr('lay-filter','formVerify').attr('lay-submit','');
layero.keydown(function(e){
if(e.keyCode==13){
submitBtn.click();
}
});
form.on('submit(formVerify)', function(data){
$.post("student/save", data.field, function(result){
if(result.success){
layer.close(index);
table.reload('student',{where:that.where});
}
layer.msg(result.msg,{offset:'rb'});
});
});
}
})
})
});
}else if(obj.event === 'delete'){
layer.confirm('确定要删除吗?', function(index) {
$.post("student/delete", {id: data.id}, function(result){
table.reload('student',{where:that.where});
layer.close(index);
layer.msg(result.msg,{offset:'rb'});
});
});
}
后端方法都是和上面的一样,所以代码可以看上面的代码,效果和上面的也一样,只不过删除一次就只能删除一条数据。
表格编辑
在表格列属性中设置edit: 'text',设置该列单元格可编辑。
{field: 'grade', title: '成绩', edit: 'text' },
效果。
通过table.on('edit(student)', function(obj){})方法监听编辑。
获取值。
obj.value //得到修改后的值
obj.field //当前编辑的字段名
obj.data //所在行的所有相关数据
JS方法代码,成绩改变后,向后台发送请求修改对应学生的成绩。因为成绩是double类型的,所以需要做一下验证
table.on('edit(student)', function(obj){
var regPos = /^\d+(\.\d+)?$/; //非负浮点数
var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
var val = obj.value == ""? 0: obj.value;
if(regPos.test(val) || regNeg.test(val)) {
$.post('student/updateGrade', {id: obj.data.id, grade: val}, function(){
});
} else {
layer.msg("请输入有效的成绩");
}
});
后台对应修改成绩方法。
@RequestMapping(value="/updateGrade")
@ResponseBody
public Object updateGrade(Integer id, double grade) {
try {
Student stu = studentService.findById(id);
stu.setGrade(grade);
studentService.save(stu);
return new AjaxResult("数据修改成功");
}catch (Exception e) {
return new AjaxResult(false, "数据修改失败");
}
}
表格内插入开关组件
表格内插入开关组件,也是比较常用的。首先需要定义开关组件代码。d为当前行对象,其中isUsed为是否毕业,Boolean类型。
<script type="text/html" id="switchTpl">
<input type="checkbox" name="isUsed" value="{{d.id}}" lay-skin="switch" lay-text="是|否" lay-filter="isUsedDemo" {{ d.isUsed == 1 ? 'checked' : '' }}>
</script>
添加开关组件列。
{field: 'isUsed', templet: '#switchTpl', title: '是否毕业' },
通过form.on('switch(isUsedDemo)', function(obj){})方法监听开关状态改变。其中isUsedDemo对应的是开关组件中lay-filter的属性值。
JS方法代码,开关组件中的value值为当前行的id,自己定义的。obj.elem.checked为开关改变后的状态。
form.on('switch(isUsedDemo)', function(obj){
$.post('student/update', {id: this.value, isUsed: obj.elem.checked}, function(){
});
});
后台修改方法。
@RequestMapping(value="/update")
@ResponseBody
public Object update(Integer id, Boolean isUsed) {
try {
Student stu = studentService.findById(id);
stu.setIsUsed(isUsed);
studentService.save(stu);
return new AjaxResult("数据修改成功");
}catch (Exception e) {
return new AjaxResult(false, "数据修改失败");
}
}
页面效果。
就写到这里了,有什么问题欢迎下方留言。如果对你有帮助,点赞关注一下呗^_^,留下你的足迹。