LayUi 树形组件tree 实现懒加载模式,展开父节点时异步加载子节点数据
LayUi框架中树形组件tree官方还在持续完善中,目前最新版本为v2.5.5
官方树形组件目前还不支持懒加载方式,之前我修改一版是通过reload重载实例方法填充子节点数据方式,因为递归页面元素时存在效率问题,最终放弃升级。
本次重新star了官方最新tree.js源码,在其基础上扩展了子节点懒加载模式方法,data数据参数中增加了lazy: true,开启懒加载模式,需要配合spread事件使用。
部分源码修改截图:
调用例子:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <meta name="renderer" content="webkit|ie-comp|ie-stand"> <meta http-equiv="hg-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta http-equiv="Cache-Control" content="no-siteapp" /> <link rel="stylesheet" href="./css/font.css"> <link rel="stylesheet" href="../lib/layui/css/layui.css" media="all"> <link rel="stylesheet" href="./lib/admin/admin.css" media="all"> <link rel="stylesheet" href="./lib/Scrollbar/jquery.scrollbar.css"> <script type="text/javascript" src="./lib/admin/jquery-1.9.1.min.js"></script> <script type="text/javascript" src="./lib/Scrollbar/jquery.scrollBar.js"></script> <script type="text/javascript" src="./lib/layui/layui.js"></script> <script type="text/javascript" src="./lib/admin/admin.js"></script> <!--[if lt IE 9]> <script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script> <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script> <![endif]--> <style> .demo-tree{ width: 500px; height: 200px; } .demo-tree-box{ width: 500px; height: 200px;border: 1px #eee solid;overflow-y: auto; } .demo-input-tree{ height: auto; width: 100%; display: none; position: absolute; top: 100%; background-color: #fff; z-index: 100; max-height: 400px; } .layui-input{ width: 500px; cursor: pointer; } </style> </head> <body class="layui-body-content"> <div class="layui-fluid"> <div class="layui-card"> <div class="layui-form layui-card-header layui-card-header-auto"> <div class="layui-form-item"> <label class="layui-form-label">部门:</label> <div class="layui-inline"> <input type="text" name="dept" lay-verify="required" placeholder="请选择部门" autocomplete="off" class="layui-input" readonly="true"> <div id="treeinputid" class="demo-input-tree demo-tree-box"></div> </div> <div class="layui-inline layui-show-xs-block"> <button class="layui-btn layui-btn-lg layui-btn-normal" lay-submit lay-filter="sreach"><i class="layui-icon layui-icon-lg"></i></button> </div> </div> </div> <div class="layui-card-body"> <div class="layui-card-header"> <button class="layui-btn layui-btn-lg layui-btn-normal" onclick="getChecked()"><i class="layui-icon"></i>获取选中</button> <button class="layui-btn layui-btn-lg layui-btn-warm" onclick="setChecked()"><i class="layui-icon"></i>设置节点勾选</button> <button class="layui-btn layui-btn-lg layui-btn-danger" onclick="reload()"><i class="layui-icon"></i>实例重载</button> </div> <div class="demo-tree"> <div id="treeid" class="demo-tree demo-tree-box"></div> </div> </div> </div> <div class="layui-floor"> <blockquote class="layui-elem-quote layui-quote-nm">Copyright©2019-2020, 本系统由@一如既往,提供技术支持! </blockquote> </div> </div> </body> <script> //初始化 layui.use(['tree'], function () { var tree = layui.tree; //treeid var inst1 = tree.render({ elem: '#treeid', id: 'treeid', //定义索引 showCheckbox: true, //是否显示复选框 showLine: true, //是否开启连接线。默认 true,若设为 false,则节点左侧出现三角图标。 accordion: false, //是否开启手风琴模式,默认 false onlyIconControl: false, //是否仅允许节点左侧图标控制展开收缩。默认 false isJump: false, //是否允许点击节点时弹出新窗口跳转。默认 false data: [{ id: 'hg-100', field: '1', level: '1', title: '父节点100', spread: true, children: [{ id: 'hg-100101', field: '3', level: '2', title: '子节点100101', children: [{ id: 'hg-100101101', field: '4', level: '3', title: '子节点100101101' }, { id: 'hg-100101102', field: '5', level: '3', title: '子节点100101102' }, { id: 'hg-100101103', field: '6', level: '3', title: '子节点100101103' }] }] }, { id: 'hg-200', field: '2', level: '1', title: '父节点200', lazy: true }], text: { defaultNodeName: '无数据', none: '加载数据失败!' }, click: function (obj) { console.log(obj.data); //得到当前点击的节点数据 console.log(obj.state); //得到当前节点的展开状态:open、close、normal console.log(obj.elem); //得到当前节点元素 console.log(obj.data.children); //当前节点下是否有子节点 }, oncheck: function (obj) { console.log(obj.data); //得到当前点击的节点数据 console.log(obj.checked); //得到当前节点的展开状态:open、close、normal console.log(obj.elem); //得到当前节点元素 }, spread: function (obj) { console.log(obj); if(obj.state=='open'){ setTimeout(() => { tree.lazytree(inst1.config.id, obj.elem, getTreeJson(obj.data.id)); }, 2000); } } }); //treeinput var inst2; $("[name='dept']").on("click",function (e) { e.stopPropagation(); const deprt = this; if(!inst2){ inst2 = tree.render({ elem: '#treeinputid', id: 'treeinputid', //定义索引 showCheckbox: true, //是否显示复选框 showLine: true, //是否开启连接线。默认 true,若设为 false,则节点左侧出现三角图标。 accordion: false, //是否开启手风琴模式,默认 false onlyIconControl: false, //是否仅允许节点左侧图标控制展开收缩。默认 false isJump: false, //是否允许点击节点时弹出新窗口跳转。默认 false data: [{ id: 'hg-100', field: '1', level: '1', title: '父节点100', spread: true, children: [{ id: 'hg-100101', field: '3', level: '2', title: '子节点100101', children: [{ id: 'hg-100101101', field: '4', level: '3', title: '子节点100101101' }, { id: 'hg-100101102', field: '5', level: '3', title: '子节点100101102' }, { id: 'hg-100101103', field: '6', level: '3', title: '子节点100101103' }] }] }, { id: 'hg-200', field: '2', level: '1', title: '父节点200', lazy: true }], text: { defaultNodeName: '无数据', none: '加载数据失败!' }, click: function (obj) { console.log(obj.data); //得到当前点击的节点数据 console.log(obj.state); //得到当前节点的展开状态:open、close、normal console.log(obj.elem); //得到当前节点元素 console.log(obj.data.children); //当前节点下是否有子节点 }, oncheck: function (obj) { var checkData = tree.getChecked(inst2.config.id); var map = getmap(checkData); $(deprt).val(map.value.join(',')); }, spread: function (obj) { console.log(obj); if(obj.state=='open'){ setTimeout(() => { tree.lazytree(inst2.config.id, obj.elem, getTreeJson(obj.data.id)); }, 2000); } } }); } $("#treeinputid").toggle(); }) //监听表单提交事件 hg.form.onsubmit('sreach', function (data) { $("#treeinputid").hide(); var checkData = tree.getChecked(inst2.config.id); var map = getmap(checkData); var init = map.result; hg.msg(JSON.stringify(init)); }); const getmap = (target, result = []) => { layui.each(target,(i,e)=>{ e.id && result.push({id:e.id,title:e.title}); e.children && getmap(e.children, result); }); let titles = result.map(e=>{return e.title}); return {value:titles,result:result}; }; }); // 模拟后台返回数据 function getTreeJson(id) { if (id === 'hg-200') { return [{ id: 'hg-200101', level: '2', title: '子节点200101' }, { id: 'hg-200102', level: '2', title: '子节点200102', lazy: true }]; } if (id === 'hg-200102') { return [{ id: 'hg-200102101', level: '3', title: '子节点200102101' }, { id: 'hg-200102102', level: '3', title: '子节点200102102', lazy: true }]; } if (id === 'hg-200102102') { return [{ id: 'hg-200102102101', level: '4', title: '子节点200102102101' }, { id: 'hg-200102102102', level: '4', title: '子节点200102102102', }]; } } //获得选中的节点 function getChecked(){ layui.use(['tree'], function () { var tree = layui.tree; var checkData = tree.getChecked('treeid'); hg.msg(JSON.stringify(checkData)); }); } //设置节点勾选 function setChecked(){ layui.use(['tree'], function () { var tree = layui.tree; tree.setChecked('treeid', ['hg-100101101','hg-100101102']); }); } //实例重载 function reload(){ layui.use(['tree'], function () { var tree = layui.tree; tree.reload('treeid', { }); }); } </script> </html>
<script> //初始化 layui.use(['tree'], function () { var tree = layui.tree; //treeid var inst1 = tree.render({ elem: '#treeid', id: 'treeid', //定义索引 showCheckbox: true, //是否显示复选框 showLine: true, //是否开启连接线。默认 true,若设为 false,则节点左侧出现三角图标。 accordion: false, //是否开启手风琴模式,默认 false onlyIconControl: false, //是否仅允许节点左侧图标控制展开收缩。默认 false isJump: false, //是否允许点击节点时弹出新窗口跳转。默认 false data: [{ id: 'hg-100', field: '1', level: '1', title: '父节点100', spread: true, children: [{ id: 'hg-100101', field: '3', level: '2', title: '子节点100101', children: [{ id: 'hg-100101101', field: '4', level: '3', title: '子节点100101101' }, { id: 'hg-100101102', field: '5', level: '3', title: '子节点100101102' }, { id: 'hg-100101103', field: '6', level: '3', title: '子节点100101103' }] }] }, { id: 'hg-200', field: '2', level: '1', title: '父节点200', lazy: true }], text: { defaultNodeName: '无数据', none: '加载数据失败!' }, click: function (obj) { console.log(obj.data); //得到当前点击的节点数据 console.log(obj.state); //得到当前节点的展开状态:open、close、normal console.log(obj.elem); //得到当前节点元素 console.log(obj.data.children); //当前节点下是否有子节点 }, oncheck: function (obj) { console.log(obj.data); //得到当前点击的节点数据 console.log(obj.checked); //得到当前节点的展开状态:open、close、normal console.log(obj.elem); //得到当前节点元素 }, spread: function (obj) { console.log(obj); if(obj.state=='open'){ setTimeout(() => { tree.lazytree(inst1.config.id, obj.elem, getTreeJson(obj.data.id)); }, 2000); } } }); //treeinput var inst2; $("[name='dept']").on("click",function (e) { e.stopPropagation(); const deprt = this; if(!inst2){ inst2 = tree.render({ elem: '#treeinputid', id: 'treeinputid', //定义索引 showCheckbox: true, //是否显示复选框 showLine: true, //是否开启连接线。默认 true,若设为 false,则节点左侧出现三角图标。 accordion: false, //是否开启手风琴模式,默认 false onlyIconControl: false, //是否仅允许节点左侧图标控制展开收缩。默认 false isJump: false, //是否允许点击节点时弹出新窗口跳转。默认 false data: [{ id: 'hg-100', field: '1', level: '1', title: '父节点100', spread: true, children: [{ id: 'hg-100101', field: '3', level: '2', title: '子节点100101', children: [{ id: 'hg-100101101', field: '4', level: '3', title: '子节点100101101' }, { id: 'hg-100101102', field: '5', level: '3', title: '子节点100101102' }, { id: 'hg-100101103', field: '6', level: '3', title: '子节点100101103' }] }] }, { id: 'hg-200', field: '2', level: '1', title: '父节点200', lazy: true }], text: { defaultNodeName: '无数据', none: '加载数据失败!' }, click: function (obj) { console.log(obj.data); //得到当前点击的节点数据 console.log(obj.state); //得到当前节点的展开状态:open、close、normal console.log(obj.elem); //得到当前节点元素 console.log(obj.data.children); //当前节点下是否有子节点 }, oncheck: function (obj) { var checkData = tree.getChecked(inst2.config.id); var map = getmap(checkData); $(deprt).val(map.value.join(',')); }, spread: function (obj) { console.log(obj); if(obj.state=='open'){ setTimeout(() => { tree.lazytree(inst2.config.id, obj.elem, getTreeJson(obj.data.id)); }, 2000); } } }); } $("#treeinputid").toggle(); }) //监听表单提交事件 hg.form.onsubmit('sreach', function (data) { $("#treeinputid").hide(); var checkData = tree.getChecked(inst2.config.id); var map = getmap(checkData); var init = map.result; hg.msg(JSON.stringify(init)); }); const getmap = (target, result = []) => { layui.each(target,(i,e)=>{ e.id && result.push({id:e.id,title:e.title}); e.children && getmap(e.children, result); }); let titles = result.map(e=>{return e.title}); return {value:titles,result:result}; }; }); // 模拟后台返回数据 function getTreeJson(id) { if (id === 'hg-200') { return [{ id: 'hg-200101', level: '2', title: '子节点200101' }, { id: 'hg-200102', level: '2', title: '子节点200102', lazy: true }]; } if (id === 'hg-200102') { return [{ id: 'hg-200102101', level: '3', title: '子节点200102101' }, { id: 'hg-200102102', level: '3', title: '子节点200102102', lazy: true }]; } if (id === 'hg-200102102') { return [{ id: 'hg-200102102101', level: '4', title: '子节点200102102101' }, { id: 'hg-200102102102', level: '4', title: '子节点200102102102', }]; } } //获得选中的节点 function getChecked(){ layui.use(['tree'], function () { var tree = layui.tree; var checkData = tree.getChecked('treeid'); hg.msg(JSON.stringify(checkData)); }); } //设置节点勾选 function setChecked(){ layui.use(['tree'], function () { var tree = layui.tree; tree.setChecked('treeid', ['hg-100101101','hg-100101102']); }); } //实例重载 function reload(){ layui.use(['tree'], function () { var tree = layui.tree; tree.reload('treeid', { }); }); } </script>
【HG-Layui-UI通用后台管理框架V1.0版】
下载地址:
https://www.cnblogs.com/han1982/p/12003454.html
tree.js 下载地址在回复区可见。(layui-v2.5.5版本替换tree.js可用)