拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Layui+Layer 弹出层实现 CRUD:AJAX 无刷新新增修改删除后台实战

一、业务效果说明列表页面不跳转点击【添加流派】layer.open 弹出弹窗表单填写数据 AJAX 提交提交成功关闭弹窗局部刷新表格列表。点击每行【修改】按钮发送 AJAX 请求查询单条数据回显到弹窗表单编辑提交更新数据库。点击【删除】按钮弹出 layer.confirm 确认提示框确认之后执行删除无刷新更新列表。表单校验正则校验输入内容异步 AJAX 校验流派名称是否重复。核心所有操作停留在列表页不发生页面跳转用户体验更好。二、项目引入 Layui 资源把 layui 静态资源css、js放入 webapp在 jsp 页面头部引入!--引入jQuery layui -- script src/js/jquery-3.3.1.min.js/script link relstylesheet href/layui/css/layui.css script src/layui/layui.js/script三、列表页面 HTML 片段列表页面隐藏新增弹窗 div、修改弹窗 div默认 display:nonelayer.open 动态渲染。% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % %--列表表单用于分页、搜索提交--% form idlistForm action/mtype/list methodget input typehidden namepageNo idpageNo value${page.pageNo} input typetext nametname value${mq.tname} placeholder流派名称搜索 button typesubmit搜索/button /form button idaddBtn classlayui-btn layui-btn-normal添加流派/button table classlayui-table thead tr th编号/th th流派名称/th th流派描述/th th操作/th /tr /thead tbody c:forEach items${page.list} varitem tr td${item.tid}/td td${item.tname}/td td${item.tdesc}/td td button classlayui-btn layui-btn-xs edit-btn>script var addLayerIndex; //新增弹窗索引用于关闭弹窗 var updateLayerIndex; //修改弹窗索引 layui.use([form,layer],function () { var form layui.form; var layer layui.layer; //自定义表单校验正则 异步校验流派名称是否重复 form.verify({ checkName:function (value,item) { //正则只能中文、字母、数字1‑20位 if(!/^[\u4e00‑\u9a5fa‑zA‑Z0‑9]{1,20}$/.test(value)){ return 名称只能是中英文、数字长度1‑20; } var flag true; //异步校验必须设置 async:false 同步等待结果校验器需要拿到返回结果 $.ajax({ url:/mtype/checkName, type:post, data:{tname:value}, async:false, success:function (resp) { if(resp exist){ flag false; } } }) if(!flag){ return 该流派名称已经存在; } } }); //1、打开新增弹窗 $(#addBtn).click(function () { //【重要】每次打开新增弹窗重置表单清除上次残留数据解决DOM缓存旧数据 $(#addForm)[0].reset(); form.render(addFilter); addLayerIndex layer.open({ type:1, title:新增流派, area:[520px,360px], content:$(#addPop) }) }); //监听新增表单提交 lay‑filteraddFilter lay‑submitaddSubmit form.on(submit(addSubmit),function (data) { $.ajax({ url:/mtype/addMtype, type:post, data:data.field, dataType:text, success:function (res) { if(res success){ layer.msg(新增成功); layer.close(addLayerIndex); //提交列表表单无刷新刷新页面列表数据 $(#listForm).submit(); }else { layer.msg(新增失败); } } }) return false; //阻止表单原生跳转提交 }); //2、修改点击修改按钮回显数据打开弹窗 $(.edit-btn).click(function () { var tid $(this).data(tid); //请求后端获取单条数据 $.ajax({ url:/mtype/getMtype, type:post, data:{tid:tid}, dataType:json, success:function (obj) { //给修改表单赋值 form.val(updateFilter,obj); updateLayerIndex layer.open({ type:1, title:修改流派, area:[520px,360px], content:$(#updatePop) }) } }) }); //监听修改表单提交 form.on(submit(updateSubmit),function (data) { $.ajax({ url:/mtype/updateMtype, type:post, data:data.field, dataType:text, success:function (res) { if(res success){ layer.msg(修改成功); layer.close(updateLayerIndex); $(#listForm).submit(); }else{ layer.msg(修改失败); } } }) return false; }); //3、删除功能 layer.confirm确认弹窗 $(.del-btn).click(function () { var tid $(this).data(tid); layer.confirm(确定删除该流派吗删除后不可恢复,{icon:3,title:删除确认},function (index) { $.ajax({ url:/mtype/delMtype, type:post, data:{tid:tid}, dataType:text, success:function (res) { if(res success){ layer.msg(删除成功); layer.close(index); $(#listForm).submit(); }else{ layer.msg(删除失败); } } }) }) }) }) /script关键点说明return false阻止 form 表单原生跳转提交完全交给 AJAX 异步处理。form.render(filterName)layui 表单 DOM 改变后必须重新渲染否则输入框、校验不生效。异步校验名字重复async:false必须同步校验函数要拿到 ajax 返回结果。layer.open 拿到返回的 index用于layer.close(index)关闭指定弹窗。五、SSM Controller 后端代码package cn.tx.controller; import cn.tx.model.Mtype; import cn.tx.query.MtypeQuery; import cn.tx.service.MtypeService; import cn.tx.util.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; Controller RequestMapping(/mtype) public class MtypeController { Autowired private MtypeService mtypeService; //列表分页上篇博客通用分页 RequestMapping(/list) public String list(MtypeQuery mq, Model model){ if(mq.getPageNo() null){ mq.setPageNo(1); } PageMtype page mtypeService.selectObjectByCondition(mq); model.addAttribute(page,page); model.addAttribute(mq,mq); return songtype; } //异步校验流派名称是否存在 ResponseBody PostMapping(/checkName) public String checkName(String tname){ MtypeQuery query new MtypeQuery(); query.setTname(tname); PageMtype page mtypeService.selectObjectByCondition(query); if(page.getTotalCount()0){ return exist; //名称已存在 } return ok; } //新增 ResponseBody PostMapping(/addMtype) public String addMtype(Mtype mtype){ mtypeService.insert(mtype); return success; } //根据id查询单条数据给修改弹窗回显 ResponseBody PostMapping(/getMtype) public Mtype getMtype(Integer tid){ return mtypeService.selectByPrimaryKey(tid); } //修改 ResponseBody PostMapping(/updateMtype) public String updateMtype(Mtype mtype){ mtypeService.updateByPrimaryKeySelective(mtype); return success; } //删除 ResponseBody PostMapping(/delMtype) public String delMtype(Integer tid){ mtypeService.deleteByPrimaryKey(tid); return success; } }六、高频踩坑汇总坑 1lay‑filter 名字不匹配表单 submit 完全没有触发现象点击提交按钮毫无反应js 里面的form.on(submit(xxx)不会执行。原因form标签lay‑filteraddFilter和 js 监听submit(addSubmit)里面的 filter 名称必须严格对应大小写敏感。排查复制粘贴字符串不要手敲写错。坑 2layer 弹窗关闭第二次打开弹窗还残留上次填写旧数据DOM 缓存坑原因layer.open 只是把页面中已有的 div 拿出来弹窗关闭弹窗不会删除 DOM 节点表单数据还留在内存 DOM 里面。解决方案每次打开弹窗前手动$(#addForm)[0].reset()重置表单执行form.render(addFilter)重新渲染 layui 表单。坑 3AJAX 提交成功但是页面列表不刷新现象弹窗关闭数据库数据变了表格还是旧数据。错误做法location.reload()整页刷新体验差。本项目方案$(#listForm).submit()提交列表查询表单请求后台重新拉取列表数据页面刷新列表。坑 4自定义校验做 AJAX 异步查重直接 return 结果无效现象不管名字是否重复校验永远通过。根源ajax 默认async:true异步校验函数直接 return 的时候AJAX 请求还没有返回。解决设置async:false同步等待 ajax 执行完毕拿到布尔标记再 return 提示文字。注意同步 AJAX 会阻塞浏览器少量后台管理场景可以使用高并发前台不推荐。坑 5form.val () 赋值回显修改弹窗不生效form.val 的第一个参数是lay‑filter的值不是表单 idform.val(updateFilter,obj)。实体类属性名必须和表单name属性完全一致大小写敏感。赋值之后不需要手动给 input 设置 valform.val 会自动填充全部表单元素。坑 6忘记写 return false表单触发原生页面跳转现象点击提交弹窗一瞬间页面直接跳转到/mtype/addMtype地址。form.on(submit(xxx),function(data){ ... return false; })必须写 return false阻止表单原生提交行为全部交给 AJAX 处理。坑 7layer.confirm 删除框点取消也执行删除现象不管点确认还是取消都会执行删除逻辑。原因删除逻辑写在 confirm 外面删除逻辑必须写在layer.confirm回调函数内部只有点击确定才会执行回调。七、整体开发流程小结在列表 JSP 页面写 2 份隐藏 div分别对应新增表单、修改表单设置 lay‑filter。js 监听按钮layer.open 打开弹窗打开前重置表单解决 DOM 缓存。layui form.verify 写自定义校验异步查重设置async:false。form.on 监听 lay‑submit 提交事件AJAX 提交 data.field 表单数据return false阻止原生提交。Controller 接收参数完成新增 / 修改返回success文本。成功回调关闭 layer 弹窗提交列表表单刷新页面表格。删除使用layer.confirm确认弹窗确认后执行 AJAX 删除。核心思想Layer 弹窗只是 UI 容器真正表单 DOM 仍然在列表页面因此带来缓存坑AJAX 异步交互避免页面跳转是后台管理系统主流交互方案。八、拓展思考问除了把 div 写在当前页面隐藏layer.open 还有什么方式加载弹窗答本项目方案页面内置隐藏 div弹窗渲染优点速度快不用额外请求缺点存在 DOM 缓存问题每次打开要重置表单。type:2 iframe 方式单独跳转一个 jsp 弹窗页面优点 DOM 隔离无缓存缺点需要额外发请求弹窗页面不能直接操作父页面 js 变量。后台管理系统小弹窗优先采用内置 div 的方式。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门