LayUI樹形表格treetable使用及說明
LayUI是現(xiàn)在比較流行的一款前端框架
也有很多人基于LayUI開發(fā)了很多不錯的組件,比如treetable樹形表格。
因為treetable是第三方基于LayUI開發(fā)的,所以需要先用Layui引入一下文件。
layui.config({ base : 'static/layui/' }).extend({ treetable : 'treetable-lay/treetable' });
之后先看一下顯示的效果。
之后頁面只需要引入LayUI的CSS和JS就可以了。
頁面給一個table標(biāo)簽,用于顯示treetable中的數(shù)據(jù)樣式。
<table class="layui-hide" id = "menu" lay-filter="menu"></table>
表格左上方的工具欄按鈕組件代碼。
<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請求加載數(shù)據(jù)及設(shè)置表格樣式。
yui.use(['treetable', 'table', 'layer'], function () { var table = layui.table; var layer = layui.layer; var treetable = layui.treetable; //渲染表格 var renderTable = function(){ layer.load(2); //加載層 treetable.render({ height: 'full-160', id:'menu', treeColIndex: 1, //樹形圖標(biāo)顯示在第幾列 treeSpid: '0', //最上級的父級id treeIdName: 'id', //id字段的名稱 treePidName: 'parentId', //父級節(jié)點字段 treeDefaultClose: false, //是否默認(rèn)折疊 treeLinkage: false, //父級展開時是否自動展開所有子級 elem: '#menu', //表格id url: 'menu/treedata', toolbar: '#toolbarDemo', page: false, cols: [ [ {type:'radio'}, {field: 'name', title: '菜單名稱'}, {field: 'url' , title: '地址'}, {field: 'icon' , hide : true, title: '圖標(biāo)'}, {field: 'idx', title: '排序'} ] ], //數(shù)據(jù)渲染完的回調(diào) done: function () { //關(guān)閉加載 layer.closeAll('loading'); } }) }; renderTable(); });
其中URL地址為請求數(shù)據(jù)地址。后臺對應(yīng)的方法。
@RequestMapping(value="/treedata") @ResponseBody public Object list(TbMenuForm form){ Sort sort = bulidSort(); //排序 Specification<TbMenu> spec = buildSpec(form); //查詢條件 List<TbMenu> list = menuService.findAll(spec, sort); return new TreeTableModel(list); } public Sort bulidSort() { return Sort.by("idx"); //按idx字段排序 } public Specification<TbMenu> buildSpec(TbMenuForm form){ return null; }
list方法中的TbMenuForm接收類中的字段和實體類字段差不多。其中TreeTableModel返回類為返回數(shù)據(jù)格式的工具類。
實體類TbMenu代碼
import com.fasterxml.jackson.annotation.JsonIgnore; import org.springframework.data.annotation.CreatedBy; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity public class TbMenu { private Integer id; private String name; //菜單名稱 private String url; //路徑 private String icon; //圖標(biāo) private double idx; //排序 @JsonIgnore private TbMenu parent; @JsonIgnore private List<TbMenu> children=new ArrayList<>(); @Id @GeneratedValue public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public double getIdx() { return idx; } public void setIdx(double idx) { this.idx = idx; } @ManyToOne @CreatedBy public TbMenu getParent() { return parent; } public void setParent(TbMenu parent) { this.parent = parent; } @OneToMany(cascade=CascadeType.ALL,mappedBy="parent") @OrderBy(value="idx") public List<TbMenu> getChildren() { return children; } public void setChildren(List<TbMenu> children) { this.children = children; } public TbMenu(Integer id, String name, String url, String icon, double idx, TbMenu parent, List<TbMenu> children) { this.id = id; this.name = name; this.url = url; this.icon = icon; this.idx = idx; this.parent = parent; this.children = children; } public TbMenu(Integer id) { this.id = id; } public TbMenu() { } @Transient public Integer getParentId() { return parent==null? 0 : parent.getId(); } }
TbMenuForm接收類
public class TbMenuForm { private Integer id; private String name; //菜單名稱 private String url; //路徑 private String icon; //圖標(biāo) private double idx; //排序 private Integer parentId; //父節(jié)點id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public double getIdx() { return idx; } public void setIdx(double idx) { this.idx = idx; } public Integer getParentId() { return parentId; } public void setParentId(Integer parentId) { this.parentId = parentId; } }
返回數(shù)據(jù)格式TreeTableModel類
public class TreeTableModel { private Integer code=0; private String msg="ok"; private Integer count; private List data; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } public List getData() { return data; } public void setData(List data) { this.data = data; } public TreeTableModel() { super(); // TODO Auto-generated constructor stub } public TreeTableModel(Integer code, String msg, Integer count, List data) { super(); this.code = code; this.msg = msg; this.count = count; this.data = data; } public TreeTableModel(List data) { super(); this.count=data.size(); this.data = data; } }
返回的JSON數(shù)據(jù)格式,這里需要注意的是parentId為父節(jié)點,需要和前面的JS中設(shè)置的屬性值一樣,沒有父級節(jié)點parentId需要為0,不能為null。
{ "code": 0, "msg": "ok", "count": 6, "data": [ { "id": 1, "name": "系統(tǒng)設(shè)置", "url": "", "icon": "", "idx": 1.0, "parentId": 0 //最上級節(jié)點,父節(jié)點為0 }, { "id": 2, "name": "角色管理", "url": "", "icon": "", "idx": 1.0, "parentId": 1 //上級節(jié)點 }, { "id": 6, "name": "數(shù)據(jù)表格", "url": "", "icon": "", "idx": 1.0, "parentId": 5 }, { "id": 3, "name": "部門管理", "url": "", "icon": "", "idx": 2.0, "parentId": 1 }, { "id": 5, "name": "表格案例", "url": "", "icon": "", "idx": 2.0, "parentId": 0 }, { "id": 7, "name": "樹形表格", "url": "", "icon": "", "idx": 2.0, "parentId": 5 } ] }
數(shù)據(jù)加載完成后,頁面中就可以顯示出數(shù)據(jù)了,效果如下。
使用table.on('toolbar(menu)', function(obj){})監(jiān)聽表格上面的工具類按鈕點擊事件。
監(jiān)聽工具欄的新增修改刪除和刷新按鈕方法
table.on('toolbar(menu)', function(obj){ var checkStatus = table.checkStatus('menu'); var data = checkStatus.data; if(obj.event === 'add'){ var parentId = data.length==0? 0 : data[0].id; $.get('menu/edit', {parentId: parentId}, function(data){ layer.open({ type: 1, title: '新增', area: ['530px'], content: data, btn: ['提交', '退出'], yes:function(){ }, success:function(layero,index){ layui.use('form',function(){ 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('menu/save',data.field,function(result){ if(result.success){ layer.close(index); //刷新,重新渲染表格 renderTable(); } layer.msg(result.msg,{offset:'rb'}); }); return false; }); }); } }) }) }else if(obj.event === 'updata'){ if(data.length != 1){ layer.msg("請選擇一行進(jìn)行編輯",{offset:'rb'}); }else{ var id = data[0].id; $.get('menu/edit', {id: id}, function(data){ layer.open({ type: 1, title: '修改', area: ['530px'], content: data, btn: ['提交', '退出'], yes:function(){ }, success:function(layero,index){ layui.use('form',function(){ 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('menu/save',data.field,function(result){ if(result.success){ layer.close(index); //刷新,重新渲染表格 renderTable(); } layer.msg(result.msg,{offset:'rb'}); }); return false; }); }); } }) }) } }else if(obj.event === "delete"){ if(data.length != 1){ layer.msg("請選擇一行進(jìn)行刪除",{offset:'rb'}); }else{ var id = data[0].id; layer.confirm('確定刪除選定行的數(shù)據(jù)嗎?', function(index){ $.post('menu/delete',{id:id},function(result){ if(result.success){ layer.close(index); renderTable(); } layer.msg(result.msg,{offset:'rb'}); }); }); } }else if(obj.event === "refresh"){ renderTable(); } })
其中obj.event值為點擊工具欄按鈕的lay-event屬性值。
新增和修改方法,先請求后臺menu/edit獲取到新增修改的頁面,把頁面用LayUI的layer彈框顯示出來。這里新增和修改用的是一個方法和一個頁面。修改時傳遞了一個id參數(shù),用于查詢修改的數(shù)據(jù)和區(qū)別新增還是修改。新增時如果選中了一行,會把當(dāng)前行的id作為參數(shù),傳遞到后臺,相當(dāng)于默認(rèn)的父節(jié)點id。
跳轉(zhuǎn)到新增和修改頁面的edit后臺方法。如果修改就把當(dāng)前修改的數(shù)據(jù)傳遞到前臺,新增時,如果有選中的節(jié)點,就把選中節(jié)點的id作為父節(jié)點id傳遞到前臺。
@Override public void edit(TbMenuForm form, ModelMap map) throws InstantiationException, IllegalAccessException { TbMenu model = new TbMenu(); Integer id = form.getId(); if(id != null) { model = menuService.findById(id); } map.put("model", model); //修改的對象,如果新增model就為null map.put("parentId", form.getParentId()); //父節(jié)點id }
edit頁面代碼,上級菜單是用LayUI的TreeSelect做的,對于TreeSelect的用法,大家可以訪問LayUI下拉樹TreeSelect的使用。
<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}" /> <div class="layui-form-item"> <label class="layui-form-label">上級菜單:</label> <div class="layui-input-block"> <input type="text" name="parentId" id="tree" lay-filter="tree" 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="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="url" th:value="${model.url}" class="layui-input" /> </div> </div> <div class="layui-form-item" > <label class="layui-form-label">圖標(biāo):</label> <div class="layui-input-block"> <input type="text" name="icon" th:value="${model.icon}" 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="idx" th:value="${model.idx}" class="layui-input" /> </div> </div> </form> <script th:inline="javascript"> layui.use(["treeSelect", "form"], function () { var form = layui.form; form.render('select'); var treeSelect = layui.treeSelect; treeSelect.render({ // 選擇器 elem: '#tree', // 數(shù)據(jù) data: 'menu/treeSelect?id='+[[${model.id==null ? 0 : model.id}]], // 異步加載方式:get/post,默認(rèn)get type: 'post', // 占位符 placeholder: '上級菜單', // 是否開啟搜索功能:true/false,默認(rèn)false search: true, // 一些可定制的樣式 style: { folder: { enable: true }, line: { enable: true } }, // 加載完成后的回調(diào)函數(shù) success: function (d) { // 選中節(jié)點,根據(jù)id篩選 treeSelect.checkNode('tree', [[${model.parent == null? parentId: model.parent.id}]]); // 刷新樹結(jié)構(gòu) treeSelect.refresh('tree'); } }); }); </script>
menu/treeSelect加載TreeSelect數(shù)據(jù)。對于TreeSelect的用法,大家可以訪問LayUI下拉樹TreeSelect的使用。
@RequestMapping(value="/treeSelect") @ResponseBody public Object treeSelect(Integer id) { Sort sort = Sort.by("idx"); //排序 Specification<TbMenu> spec = buildSpec1(); //查詢條件,可以自行添加,對應(yīng)的buildSpec1方法 List<TbMenu> list = menuService.findAll(spec,sort); return buildTree(list, id); } private Object buildTree(List<TbMenu> list, Integer id) { List<HashMap<String, Object>> result=new ArrayList<>(); for (TbMenu dept : list) { if(dept.getId() != id) { HashMap<String, Object> node=new HashMap<>(); node.put("id", dept.getId()); node.put("name",dept.getName()); node.put("open", false); node.put("checked", false); if(dept.getChildren().size() != 0) { node.put("children",buildTree(dept.getChildren(), id)); } result.add(node); } } return result; } public Specification<TbMenu> buildSpec1() { Specification<TbMenu> specification = new Specification<TbMenu>() { private static final long serialVersionUID = 1L; @Override public Predicate toPredicate(Root<TbMenu> root, CriteriaQuery<?> query, CriteriaBuilder cb) { HashSet<Predicate> rules=new HashSet<>(); Predicate parent = cb.isNull(root.get("parent")); //添加父節(jié)點為空的條件,即查詢最上級數(shù)據(jù) rules.add(parent); return cb.and(rules.toArray(new Predicate[rules.size()])); } }; return specification; }
頁面顯示效果。
后臺保存方法
@Override public Object save(TbMenuForm form) { try { TbMenu model = new TbMenu(); Integer id = form.getId(); if(id != null) { model = menuService.findById(id); } //父級菜單id Integer parentId = form.getParentId(); if(parentId == null) { model.setParent(null); }else { model.setParent(new TbMenu(parentId)); } BeanUtils.copyProperties(form, model,"id", "parent"); menuService.save(model); return new AjaxResult("數(shù)據(jù)保存成功!"); } catch (Exception e) { return new AjaxResult(false,"數(shù)據(jù)保存失敗"); } }
AjaxResult類是一個請求完成返回的一個工具類。
import java.util.HashMap; import org.springframework.data.domain.Page; 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; } }
新增和修改就完了,下面就是刪除數(shù)據(jù)。刪除需要先判斷是否選中了一行。然后把選中行的id作為參數(shù),傳遞到后臺,根據(jù)id刪除數(shù)據(jù)就可以了。
if(data.length != 1){ layer.msg("請選擇一行進(jìn)行刪除",{offset:'rb'}); }else{ var id = data[0].id; layer.confirm('確定刪除選定行的數(shù)據(jù)嗎?', function(index){ $.post('menu/delete',{id:id},function(result){ if(result.success){ layer.close(index); renderTable(); } layer.msg(result.msg,{offset:'rb'}); }); }); }
最后一個就是刷新了,刷新只需要把表格刷新一下就可以了,調(diào)用一下表格刷新方法。
renderTable();
這里持久層框架用的Spring-Data-Jpa,但只要數(shù)據(jù)傳遞到后臺了,怎么處理都差不多,請求的數(shù)據(jù)只要按照規(guī)定的JSON格式返回就可以了。后臺方法代碼上面基本的有,前臺頁面代碼有些零散,下面是顯示頁面完整代碼。
<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> <table class="layui-hide" id = "menu" lay-filter="menu"></table> <script type="text/javascript"> layui.use(['treetable', 'table', 'layer'], function () { var table = layui.table; var layer = layui.layer; var treetable = layui.treetable; //渲染表格 var renderTable = function(){ layer.load(2); //加載層 treetable.render({ height: 'full-160', id:'menu', treeColIndex: 1, //樹形圖標(biāo)顯示在第幾列 treeSpid: '0', //最上級的父級id treeIdName: 'id', //id字段的名稱 treePidName: 'parentId', //pid字段的名稱,父級菜單id treeDefaultClose: false, //是否默認(rèn)折疊 treeLinkage: false, //父級展開時是否自動展開所有子級 elem: '#menu', //表格id url: 'menu/treedata', toolbar: '#toolbarDemo', page: false, cols: [ [ {type:'radio'}, {field: 'name', title: '菜單名稱'}, {field: 'url' , title: '地址'}, {field: 'icon' , hide : true, title: '圖標(biāo)'}, {field: 'idx', title: '排序'} ] ], //數(shù)據(jù)渲染完的回調(diào) done: function () { //關(guān)閉加載 layer.closeAll('loading'); } }) }; renderTable(); table.on('toolbar(menu)', function(obj){ var checkStatus = table.checkStatus('menu'); var data = checkStatus.data; if(obj.event === 'add'){ var parentId = data.length==0? 0 : data[0].id; $.get('menu/edit', {parentId: parentId}, function(data){ layer.open({ type: 1, title: '新增', area: ['530px'], content: data, btn: ['提交', '退出'], yes:function(){ }, success:function(layero,index){ layui.use('form',function(){ 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('menu/save',data.field,function(result){ if(result.success){ layer.close(index); //刷新,重新渲染表格 renderTable(); } layer.msg(result.msg,{offset:'rb'}); }); return false; }); }); } }) }) }else if(obj.event === 'updata'){ if(data.length != 1){ layer.msg("請選擇一行進(jìn)行編輯",{offset:'rb'}); }else{ var id = data[0].id; $.get('menu/edit', {id: id}, function(data){ layer.open({ type: 1, title: '修改', area: ['530px'], content: data, btn: ['提交', '退出'], yes:function(){ }, success:function(layero,index){ layui.use('form',function(){ 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('menu/save',data.field,function(result){ if(result.success){ layer.close(index); //刷新,重新渲染表格 renderTable(); } layer.msg(result.msg,{offset:'rb'}); }); return false; }); }); } }) }) } }else if(obj.event === "delete"){ if(data.length != 1){ layer.msg("請選擇一行進(jìn)行刪除",{offset:'rb'}); }else{ var id = data[0].id; layer.confirm('確定刪除選定行的數(shù)據(jù)嗎?', function(index){ $.post('menu/delete',{id:id},function(result){ if(result.success){ layer.close(index); renderTable(); } layer.msg(result.msg,{offset:'rb'}); }); }); } }else if(obj.event === "refresh"){ renderTable(); } }) }) </script>
推薦文章,LayUI樹形結(jié)構(gòu)tree的使用
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
javascript ie6兼容position:fixed實現(xiàn)思路
positon:fixed 讓HTML元素脫離文檔流固定在瀏覽器的某個位置,由于網(wǎng)頁中類似這樣的元素很多,所以本文的出現(xiàn)是很有必要的了,接下為大家介紹下javascript如何實現(xiàn)ie6下的position:fixed2013-04-04javascript控制在光標(biāo)位置插入文字適合表情的插入
使用javascript控制在光標(biāo)位置插入文字,在實現(xiàn)表情的插入時會用到的,需要的朋友可以參考下2014-06-06JavaScript拆分字符串時產(chǎn)生空字符的解決方案
使用JavaScript的split方法拆分字符串時出現(xiàn)一些空字符串"",尤其是當(dāng)使用正則表達(dá)式作為分隔符的時候。那么,產(chǎn)生這些空字符串的原因是什么?又該如何來處理呢,這就是今天我們要探討的問題2014-09-09js中字符串編碼函數(shù)escape()、encodeURI()、encodeURIComponent()區(qū)別詳解
JavaScript中有三個可以對字符串編碼的函數(shù),分別是: escape,encodeURI,encodeURIComponent,相應(yīng)3個解碼函數(shù):unescape,decodeURI,decodeURIComponent 。接下來通過本文給大家介紹三者之家的區(qū)別,感興趣的朋友一起學(xué)習(xí)吧2016-04-04