From b468fdc463e6fc585e9473268c47e5c001a04f48 Mon Sep 17 00:00:00 2001 From: sunxb <470459819@qq.com> Date: Thu, 23 Feb 2023 11:07:12 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8B=E6=8B=89?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E5=88=9D=E5=A7=8B=E5=8C=96=E7=AB=8B=E5=8D=B3?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E7=9A=84=E6=97=B6=E5=80=99=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E8=A7=A6=E5=8F=91ready=E5=9B=9E=E8=B0=83=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=9B=E4=B8=8B=E6=8B=89=E8=8F=9C=E5=8D=95=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=95=B0=E6=8D=AEdisabled=E7=A6=81=E7=94=A8=E9=83=A8?= =?UTF-8?q?=E5=88=86=E9=80=89=E9=A1=B9=E7=82=B9=E5=87=BB=E7=9A=84=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=9B=E4=B8=8B=E6=8B=89=E8=8F=9C=E5=8D=95=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=9C=A8=E5=BC=B9=E5=87=BA=E9=80=89=E9=A1=B9=E7=9A=84?= =?UTF-8?q?=E6=97=B6=E5=80=99=E5=A6=82=E6=9E=9C=E5=BD=93=E5=89=8D=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E6=9C=89=E5=8E=86=E5=8F=B2=E7=9A=84=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E7=9B=B4=E6=8E=A5=E8=BF=9B=E8=A1=8C=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E6=9B=BF=E6=8D=A2=EF=BC=8C=E4=B8=8D=E4=BC=9A=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E5=8E=BB=E6=8E=89=E6=97=A7=E9=9D=A2=E6=9D=BF=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E5=88=9B=E5=BB=BA=E4=B8=80=E4=B8=AA=E6=96=B0=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E4=BC=98=E5=8C=96reload=E7=9A=84=E4=BD=93=E9=AA=8C?= =?UTF-8?q?=EF=BC=9B=E8=A1=A8=E6=A0=BC=E4=BF=AE=E5=A4=8Dpage=E5=BC=80?= =?UTF-8?q?=E5=90=AF=E7=9A=84=E6=97=B6=E5=80=99data=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=BE=9D=E6=97=A7=E5=8F=97limit=E9=99=90=E5=88=B6=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=9Btable=E4=BF=AE=E5=A4=8Dresize?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E5=9C=A8=E6=97=A0=E6=95=B0=E6=8D=AE=E6=88=96?= =?UTF-8?q?=E8=80=85=E8=AF=B7=E6=B1=82=E5=BC=82=E5=B8=B8=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5=E4=B8=8B=E5=8F=B3=E5=9B=BA=E5=AE=9A=E5=88=97=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=87=BA=E6=9D=A5=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/dropdown.js | 70 ++++++++++++++++++++++------------------- src/modules/table.js | 9 +++--- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/modules/dropdown.js b/src/modules/dropdown.js index 448441de..46312faf 100644 --- a/src/modules/dropdown.js +++ b/src/modules/dropdown.js @@ -177,9 +177,9 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ ,'-': 'layui-menu-item-divider' }; if(isChild || type){ - return ' class="'+ className[type] +'"'; + return ' class="'+ className[type] + + '"'; } - return ''; + return item.disabled ? ' class="'+STR_DISABLED+'"' : ''; }() +'>' //标题区 @@ -236,27 +236,41 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ //判断是否已经打开了下拉菜单面板 if(!rerender && options.elem.data(MOD_INDEX +'_opened')) return; - //记录模板对象 - that.elemView = $(TPL_MAIN); - that.elemView.append(options.content || getDefaultView()); - - //初始化某些属性 - if(options.className) that.elemView.addClass(options.className); - if(options.style) that.elemView.attr('style', options.style); - - //记录当前执行的实例索引 dropdown.thisId = options.id; - - //插入视图 - that.remove(); //移除非当前绑定元素的面板 - elemBody.append(that.elemView); - options.elem.data(MOD_INDEX +'_opened', true); - //遮罩 - var shade = options.shade ? ('
') : ''; - that.elemView.before(shade); - + //记录模板对象 + that.elemView = $('.' + STR_ELEM + '[lay-id="' + options.id + '"]'); + if (that.elemView.length) { + that.elemView.html(options.content || getDefaultView()); + } else { + that.elemView = $(TPL_MAIN).attr('lay-id', options.id); + that.elemView.append(options.content || getDefaultView()); + + //初始化某些属性 + if(options.className) that.elemView.addClass(options.className); + if(options.style) that.elemView.attr('style', options.style); + + //插入视图 + that.remove(); //移除非当前绑定元素的面板 + elemBody.append(that.elemView); + + options.elem.data(MOD_INDEX +'_opened', true); + + //遮罩 + var shade = options.shade ? ('
') : ''; + that.elemView.before(shade); + + //如果是鼠标移入事件,则鼠标移出时自动关闭 + if(options.trigger === 'mouseenter'){ + that.elemView.on('mouseenter', function(){ + clearTimeout(thisModule.timer); + }).on('mouseleave', function(){ + that.delayRemove(); + }); + } + } + //坐标定位 that.position(); thisModule.prevElem = that.elemView; //记录当前打开的元素,以便在下次关闭 @@ -274,7 +288,7 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ var isChild = data.child && data.child.length > 0; var isClickAllScope = options.clickScope === 'all'; // 是否所有父子菜单均触发点击事件 - if((!isChild || isClickAllScope) && data.type !== '-'){ + if((!isChild || isClickAllScope) && data.type !== '-' && !data.disabled){ var ret = typeof options.click === 'function' && options.click(data, othis); ret === false || (isChild || that.remove()); layui.stope(e); @@ -291,16 +305,9 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ thisModule.spread(elemGroup); } }); - - //如果是鼠标移入事件,则鼠标移出时自动关闭 - if(options.trigger === 'mouseenter'){ - that.elemView.on('mouseenter', function(){ - clearTimeout(thisModule.timer); - }).on('mouseleave', function(){ - that.delayRemove(); - }); - } + //组件打开完毕的事件 + typeof options.ready === 'function' && options.ready(that.elemView, options.elem); }; //位置定位 @@ -361,9 +368,6 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ that.e = e; that.render(); e.preventDefault(); - - //组件打开完毕的时间 - typeof options.ready === 'function' && options.ready(that.elemView, options.elem, that.e.target); }; //触发元素事件 diff --git a/src/modules/table.js b/src/modules/table.js index f5f5ff0d..56b6fc3b 100644 --- a/src/modules/table.js +++ b/src/modules/table.js @@ -987,10 +987,9 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ } }); } else if(layui.type(options.data) === 'array'){ //已知数据 - var res = {} - ,startLimit = curr*options.limit - options.limit + var res = {}; - res[response.dataName] = options.data.concat().splice(startLimit, options.limit); + res[response.dataName] = options.page ? options.data.concat().splice(curr*options.limit - options.limit, options.limit) : options.data.concat(); res[response.countName] = options.data.length; //记录合计行数据 @@ -1719,8 +1718,8 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ ,fixHeight = mainHeight - scollHeight; that.layFixed.find(ELEM_BODY).css('height', layMainTable.height() >= fixHeight ? fixHeight : 'auto'); - //表格宽度小于容器宽度时,隐藏固定列 - that.layFixRight[outWidth > 0 ? 'removeClass' : 'addClass'](HIDE); + //表格宽度小于容器宽度时或者数据异常(包括无数据),隐藏固定列 + that.layFixRight[table.cache[that.key].length && outWidth > 0 ? 'removeClass' : 'addClass'](HIDE); //操作栏 that.layFixRight.css('right', scollWidth - 1); From 78d9a24312b5ef3b5e2df57246896dd6255fac6a Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <470459819@qq.com> Date: Fri, 10 Mar 2023 10:06:22 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E4=BC=98=E5=8C=96dropdown=E7=9A=84reload?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=E6=96=B0=E5=A2=9EreloadDat?= =?UTF-8?q?a=E6=96=B9=E6=B3=95=E6=94=AF=E6=8C=81=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=92=8C=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/dropdown.js | 45 +++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/src/modules/dropdown.js b/src/modules/dropdown.js index 46312faf..4cdffbee 100644 --- a/src/modules/dropdown.js +++ b/src/modules/dropdown.js @@ -48,6 +48,9 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ ,reload: function(options){ that.reload.call(that, options); } + ,reloadData: function(options){ + dropdown.reloadData(id, options); + } ,close: function () { that.remove() } @@ -83,14 +86,14 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ }; //重载实例 - Class.prototype.reload = function(options){ + Class.prototype.reload = function(options, type){ var that = this; that.config = $.extend({}, that.config, options); - that.init(true); + that.init(true, type); }; //初始化准备 - Class.prototype.init = function(rerender){ + Class.prototype.init = function(rerender, type){ var that = this ,options = that.config ,elem = options.elem = $(options.elem); @@ -110,18 +113,18 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ var newThat = thisModule.getThis(elem.data(MOD_INDEX)); if(!newThat) return; - return newThat.reload(options); + return newThat.reload(options, type); } //初始化 id 参数 options.id = ('id' in options) ? options.id : that.index; - if(options.show) that.render(rerender); //初始即显示 + if(options.show) that.render(rerender, type); //初始即显示 that.events(); //事件 }; //渲染 - Class.prototype.render = function(rerender){ + Class.prototype.render = function(rerender, type){ var that = this ,options = that.config ,elemBody = $('body') @@ -177,9 +180,9 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ ,'-': 'layui-menu-item-divider' }; if(isChild || type){ - return ' class="'+ className[type] + + '"'; + return ' class="'+ className[type] +'"'; } - return item.disabled ? ' class="'+STR_DISABLED+'"' : ''; + return item.disabled ? ' class="'+ STR_DISABLED +'"' : ''; }() +'>' //标题区 @@ -241,7 +244,7 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ //记录模板对象 that.elemView = $('.' + STR_ELEM + '[lay-id="' + options.id + '"]'); - if (that.elemView.length) { + if ('reloadData' === type && that.elemView.length) { that.elemView.html(options.content || getDefaultView()); } else { that.elemView = $(TPL_MAIN).attr('lay-id', options.id); @@ -523,14 +526,34 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ }(); //重载实例 - dropdown.reload = function(id, options){ + dropdown.reload = function(id, options, type){ var that = thisModule.getThis(id); if(!that) return this; - that.reload(options); + that.reload(options, type); return thisModule.call(that); }; + // 仅重载数据 + dropdown.reloadData = function(){ + var args = $.extend([], arguments); + args[2] = 'reloadData'; + + // 重载时,与数据相关的参数 + var dataParams = new RegExp('^('+ [ + 'data', 'templet', 'content' + ].join('|') + ')$'); + + // 过滤与数据无关的参数 + layui.each(args[1], function (key, value) { + if(!dataParams.test(key)){ + delete args[1][key]; + } + }); + + return dropdown.reload.apply(null, args); + }; + //核心入口 dropdown.render = function(options){ var inst = new Class(options); From 89646cc0119213ab1a16f29952a2eb360dbb9974 Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <470459819@qq.com> Date: Fri, 10 Mar 2023 13:36:06 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E8=B0=83=E6=95=B4dropdown=20reloadData?= =?UTF-8?q?=E7=BB=86=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/dropdown.js b/src/modules/dropdown.js index 4cdffbee..a52f862b 100644 --- a/src/modules/dropdown.js +++ b/src/modules/dropdown.js @@ -244,7 +244,7 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ //记录模板对象 that.elemView = $('.' + STR_ELEM + '[lay-id="' + options.id + '"]'); - if ('reloadData' === type && that.elemView.length) { + if (type === 'reloadData' && that.elemView.length) { that.elemView.html(options.content || getDefaultView()); } else { that.elemView = $(TPL_MAIN).attr('lay-id', options.id); @@ -541,7 +541,7 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ // 重载时,与数据相关的参数 var dataParams = new RegExp('^('+ [ - 'data', 'templet', 'content' + 'data', 'templet', 'content', 'show' ].join('|') + ')$'); // 过滤与数据无关的参数 From 5d77e15fa323d4f42c0ff4517dfd4d02a22658b4 Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <470459819@qq.com> Date: Tue, 4 Apr 2023 15:26:43 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E4=B8=8B=E6=8B=89=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=96=B0=E5=A2=9EreloadData=E6=96=B9=E6=B3=95=EF=BC=9Bform?= =?UTF-8?q?=E8=B5=8B=E5=80=BC=E7=9A=84=E7=9A=84=E6=97=B6=E5=80=99=E5=AF=B9?= =?UTF-8?q?=E4=BA=8E=E5=8D=95=E9=80=89=E8=BF=9B=E8=A1=8C=E8=B0=83=E4=BC=98?= =?UTF-8?q?=EF=BC=8C=E9=87=8D=E6=96=B0=E8=B0=83=E6=95=B4=E6=AF=8F=E4=B8=AA?= =?UTF-8?q?=E9=80=89=E9=A1=B9=E7=9A=84checked=E9=81=BF=E5=85=8D=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=E5=A4=9A=E4=B8=AAchecked=E6=88=96=E8=80=85=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=B8=85=E7=A9=BA=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=9B?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E4=BF=AE=E5=A4=8D=E6=9C=89=E5=A4=9A=E7=BA=A7?= =?UTF-8?q?=E8=A1=A8=E5=A4=B4=E5=B9=B6=E4=B8=94=E6=9C=89=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=AE=BD=E5=BA=A6=E8=87=AA=E5=8A=A8=E5=88=86?= =?UTF-8?q?=E9=85=8D=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E7=9A=84=E5=AE=BD=E5=BA=A6=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=8D=A0=E6=BB=A1=E5=AE=B9=E5=99=A8=E5=AF=BC=E5=87=BA=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=E7=BC=9D=E9=9A=99=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=9B?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E8=B0=83=E6=95=B4=E5=AE=9E=E4=BE=8B=E7=9A=84?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E6=97=B6=E6=9C=BA=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?data=E6=A8=A1=E5=BC=8F=E4=B8=8B=E5=9C=A8=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=9C=BA=E4=BC=9A=E9=81=87=E5=88=B0=E7=BB=84=E4=BB=B6=E5=86=85?= =?UTF-8?q?=E9=83=A8=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98=EF=BC=9B=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E6=96=B0=E5=A2=9EgetTrHtml=E6=96=B9=E6=B3=95=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E5=B0=86=E6=95=B0=E6=8D=AE=E8=A7=A3=E6=9E=90=E8=BF=94?= =?UTF-8?q?=E5=9B=9Ehtml=E4=BB=A3=E7=A0=81=E6=96=B9=E4=BE=BF=E5=A4=96?= =?UTF-8?q?=E9=83=A8=E8=B0=83=E7=94=A8=EF=BC=9B=E6=96=B0=E5=A2=9EtreeTable?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gulpfile.js | 2 +- src/layui.js | 1 + src/modules/dropdown.js | 103 ++-- src/modules/form.js | 4 +- src/modules/table.js | 303 ++++++----- src/modules/treeTable.js | 1035 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 1270 insertions(+), 178 deletions(-) create mode 100644 src/modules/treeTable.js diff --git a/gulpfile.js b/gulpfile.js index 8fd2aafc..96bc0230 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -21,7 +21,7 @@ const config = { ,{pkg: pkg, js: ';'} ] //模块 - ,modules: 'lay,laytpl,laypage,laydate,jquery,layer,util,dropdown,slider,colorpicker,element,upload,form,table,tree,transfer,carousel,rate,flow,code' + ,modules: 'lay,laytpl,laypage,laydate,jquery,layer,util,dropdown,slider,colorpicker,element,upload,form,table,treeTable,tree,transfer,carousel,rate,flow,code' }; // 获取参数 diff --git a/src/layui.js b/src/layui.js index d1a67ad9..14559103 100644 --- a/src/layui.js +++ b/src/layui.js @@ -60,6 +60,7 @@ ,transfer: 'transfer' //穿梭框 ,tree: 'tree' //树结构 ,table: 'table' //表格 + ,treeTable: 'treeTable' //树表 ,element: 'element' //常用元素操作 ,rate: 'rate' //评分组件 ,colorpicker: 'colorpicker' //颜色选择器 diff --git a/src/modules/dropdown.js b/src/modules/dropdown.js index cafff384..c401773e 100644 --- a/src/modules/dropdown.js +++ b/src/modules/dropdown.js @@ -48,6 +48,9 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ ,reload: function(options){ that.reload.call(that, options); } + ,reloadData: function(options){ + dropdown.reloadData(id, options); + } ,close: function () { that.remove() } @@ -83,14 +86,14 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ }; //重载实例 - Class.prototype.reload = function(options){ + Class.prototype.reload = function(options, type){ var that = this; that.config = $.extend({}, that.config, options); - that.init(true); + that.init(true, type); }; // 初始化准备 - Class.prototype.init = function(rerender){ + Class.prototype.init = function(rerender, type){ var that = this; var options = that.config; @@ -113,7 +116,7 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ var newThat = thisModule.getThis(elem.data(MOD_INDEX)); if(!newThat) return; - return newThat.reload(options); + return newThat.reload(options, type); } options.elem = $(options.elem); @@ -122,13 +125,13 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ options.id = 'id' in options ? options.id : ( elem.attr('id') || that.index ); - - if(options.show) that.render(rerender); // 初始即显示 + + if(options.show || (type === 'reloadData' && that.elemView && $('body').find(that.elemView.get(0)).length)) that.render(rerender, type); //初始即显示或者面板弹出之后执行了刷新数据 that.events(); // 事件 }; //渲染 - Class.prototype.render = function(rerender){ + Class.prototype.render = function(rerender, type){ var that = this ,options = that.config ,elemBody = $('body') @@ -234,7 +237,7 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ } //主模板 - ,TPL_MAIN = ['
' + ,TPL_MAIN = ['
' ,'
'].join(''); //如果是右键事件,则每次触发事件时,将允许重新渲染 @@ -244,26 +247,39 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ if(!rerender && options.elem.data(MOD_INDEX +'_opened')) return; //记录模板对象 - that.elemView = $(TPL_MAIN); - that.elemView.append(options.content || getDefaultView()); - - //初始化某些属性 - if(options.className) that.elemView.addClass(options.className); - if(options.style) that.elemView.attr('style', options.style); - - - //记录当前执行的实例索引 - dropdown.thisId = options.id; - - //插入视图 - that.remove(); //移除非当前绑定元素的面板 - elemBody.append(that.elemView); - options.elem.data(MOD_INDEX +'_opened', true); + that.elemView = $('.' + STR_ELEM + '[lay-id="' + options.id + '"]'); + if (type === 'reloadData' && that.elemView.length) { + that.elemView.html(options.content || getDefaultView()); + } else { + that.elemView = $(TPL_MAIN); + that.elemView.append(options.content || getDefaultView()); + + //初始化某些属性 + if(options.className) that.elemView.addClass(options.className); + if(options.style) that.elemView.attr('style', options.style); + + //记录当前执行的实例索引 + dropdown.thisId = options.id; + + //插入视图 + that.remove(); //移除非当前绑定元素的面板 + elemBody.append(that.elemView); + options.elem.data(MOD_INDEX +'_opened', true); + + //遮罩 + var shade = options.shade ? ('
') : ''; + that.elemView.before(shade); + + //如果是鼠标移入事件,则鼠标移出时自动关闭 + if(options.trigger === 'mouseenter'){ + that.elemView.on('mouseenter', function(){ + clearTimeout(thisModule.timer); + }).on('mouseleave', function(){ + that.delayRemove(); + }); + } + } - //遮罩 - var shade = options.shade ? ('
') : ''; - that.elemView.before(shade); - //坐标定位 that.position(); thisModule.prevElem = that.elemView; //记录当前打开的元素,以便在下次关闭 @@ -301,15 +317,6 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ thisModule.spread(elemGroup); } }); - - //如果是鼠标移入事件,则鼠标移出时自动关闭 - if(options.trigger === 'mouseenter'){ - that.elemView.on('mouseenter', function(){ - clearTimeout(thisModule.timer); - }).on('mouseleave', function(){ - that.delayRemove(); - }); - } // 组件打开完毕的事件 typeof options.ready === 'function' && options.ready( @@ -542,14 +549,34 @@ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ }; // 重载实例 - dropdown.reload = function(id, options){ + dropdown.reload = function(id, options, type){ var that = thisModule.getThis(id); if(!that) return this; - that.reload(options); + that.reload(options, type); return thisModule.call(that); }; + // 仅重载数据 + dropdown.reloadData = function(){ + var args = $.extend([], arguments); + args[2] = 'reloadData'; + + // 重载时,与数据相关的参数 + var dataParams = new RegExp('^('+ [ + 'data', 'templet', 'content' + ].join('|') + ')$'); + + // 过滤与数据无关的参数 + layui.each(args[1], function (key, value) { + if(!dataParams.test(key)){ + delete args[1][key]; + } + }); + + return dropdown.reload.apply(null, args); + }; + // 核心入口 dropdown.render = function(options){ var inst = new Class(options); diff --git a/src/modules/form.js b/src/modules/form.js index 9b58e18d..db472973 100644 --- a/src/modules/form.js +++ b/src/modules/form.js @@ -98,9 +98,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){ itemElem[0].checked = value; } else if(type === 'radio') { // 如果为单选框 itemElem.each(function(){ - if(this.value == value ){ - this.checked = true - } + this.checked = this.value == value; }); } else { // 其它类型的表单 itemElem.val(value); diff --git a/src/modules/table.js b/src/modules/table.js index c0138e4d..9a764eaf 100644 --- a/src/modules/table.js +++ b/src/modules/table.js @@ -46,11 +46,6 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ ,options = that.config ,id = options.id || options.index; - if(id){ - thisTable.that[id] = that; // 记录当前实例对象 - thisTable.config[id] = options; // 记录当前实例配置项 - } - return { config: options ,reload: function(options, deep){ @@ -322,10 +317,13 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ options.where = options.where || {}; // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 - options.id = 'id' in options ? options.id : ( + var id = options.id = 'id' in options ? options.id : ( options.elem.attr('id') || that.index ); + thisTable.that[id] = that; // 记录当前实例对象 + thisTable.config[id] = options; // 记录当前实例配置项 + //请求参数的自定义格式 options.request = $.extend({ pageName: 'page' @@ -810,13 +808,20 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ if(that.autoColNums > 0 && patchNums >= -colNums && patchNums <= colNums){ var getEndTh = function(th){ - var field; + var field, thRet; th = th || that.layHeader.eq(0).find('thead th:last-child') - field = th.data('field'); + layui.each(th, function (thIndex, thElem) { + thElem = $(thElem); + if (!thElem.children('.'+ELEM_GROUP).length) { // 排除合并表头 + field = thElem.attr('data-field'); + thRet = thElem; + } + }) + if(!field && th.prev()[0]){ return getEndTh(th.prev()) } - return th + return thRet } ,th = getEndTh() ,key = th.data('key'); @@ -1034,6 +1039,152 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ } }; + Class.prototype.getTrHtml = function(data, sort, curr, trsObj) { + var that = this; + var options = that.config; + var trs = trsObj && trsObj.trs || []; + var trs_fixed = trsObj && trsObj.trs_fixed || []; + var trs_fixed_r = trsObj && trsObj.trs_fixed_r || []; + curr = curr || 1 + + layui.each(data, function(i1, item1){ + var tds = [], tds_fixed = [], tds_fixed_r = [] + ,numbers = i1 + options.limit*(curr - 1) + 1; // 序号 + + // 数组值是否为 object,如果不是,则自动转为 object + if(typeof item1 !== 'object'){ + data[i1] = item1 = {LAY_KEY: item1}; + try { + table.cache[that.key][i1] = item1; + } catch(e) {} + } + + //若数据项为空数组,则不往下执行(因为删除数据时,会将原有数据设置为 []) + if(layui.type(item1) === 'array' && item1.length === 0) return; + + // 加入序号保留字段 + item1[table.config.numbersName] = numbers; + + // 记录下标索引,用于恢复排序 + if(!sort) item1[table.config.indexName] = i1; + + // 遍历表头 + that.eachCols(function(i3, item3){ + var field = item3.field || i3; + var key = item3.key; + var content = item1[field]; + + if(content === undefined || content === null) content = ''; + if(item3.colGroup) return; + + // td 内容 + var td = ['' + ,'
' + + function(){ + var tplData = $.extend(true, { + LAY_COL: item3 + }, item1); + var checkName = table.config.checkName; + var disabledName = table.config.disabledName; + + //渲染不同风格的列 + switch(item3.type){ + case 'checkbox': // 复选 + return ''; + break; + case 'radio': // 单选 + if(tplData[checkName]){ + that.thisCheckedRowIndex = i1; + } + return ''; + break; + case 'numbers': + return numbers; + break; + }; + + //解析工具列模板 + if(item3.toolbar){ + return laytpl($(item3.toolbar).html()||'').render(tplData); + } + return parseTempData.call(that, { + item3: item3 + ,content: content + ,tplData: tplData + }); + }() + ,'
'].join(''); + + tds.push(td); + if(item3.fixed && item3.fixed !== 'right') tds_fixed.push(td); + if(item3.fixed === 'right') tds_fixed_r.push(td); + }); + + trs.push(''+ tds.join('') + ''); + trs_fixed.push(''+ tds_fixed.join('') + ''); + trs_fixed_r.push(''+ tds_fixed_r.join('') + ''); + }); + + return { + trs: trs, + trs_fixed: trs_fixed, + trs_fixed_r: trs_fixed_r + } + } + + // 返回行节点代码 + table.getTrHtml = function (id, data) { + var that = getThisTable(id); + return that.getTrHtml(data); + } // 数据渲染 Class.prototype.renderData = function(opts){ @@ -1057,7 +1208,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ options.HAS_SET_COLS_PATCH || that.setColsPatch(); options.HAS_SET_COLS_PATCH = true; - var thisCheckedRowIndex; + that.thisCheckedRowIndex = ''; if(!sort && that.sortKey){ return that.sort({ field: that.sortKey.field, @@ -1066,130 +1217,10 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ reloadType: opts.type }); } - layui.each(data, function(i1, item1){ - var tds = [], tds_fixed = [], tds_fixed_r = [] - ,numbers = i1 + options.limit*(curr - 1) + 1; // 序号 - - // 数组值是否为 object,如果不是,则自动转为 object - if(typeof item1 !== 'object'){ - data[i1] = item1 = {LAY_KEY: item1}; - try { - table.cache[that.key][i1] = item1; - } catch(e) {} - } - - //若数据项为空数组,则不往下执行(因为删除数据时,会将原有数据设置为 []) - if(layui.type(item1) === 'array' && item1.length === 0) return; - - // 加入序号保留字段 - item1[table.config.numbersName] = numbers; - - // 记录下标索引,用于恢复排序 - if(!sort) item1[table.config.indexName] = i1; - - // 遍历表头 - that.eachCols(function(i3, item3){ - var field = item3.field || i3; - var key = item3.key; - var content = item1[field]; - - if(content === undefined || content === null) content = ''; - if(item3.colGroup) return; - - // td 内容 - var td = ['' - ,'
' - + function(){ - var tplData = $.extend(true, { - LAY_COL: item3 - }, item1); - var checkName = table.config.checkName; - var disabledName = table.config.disabledName; - - //渲染不同风格的列 - switch(item3.type){ - case 'checkbox': // 复选 - return ''; - break; - case 'radio': // 单选 - if(tplData[checkName]){ - thisCheckedRowIndex = i1; - } - return ''; - break; - case 'numbers': - return numbers; - break; - }; - - //解析工具列模板 - if(item3.toolbar){ - return laytpl($(item3.toolbar).html()||'').render(tplData); - } - return parseTempData.call(that, { - item3: item3 - ,content: content - ,tplData: tplData - }); - }() - ,'
'].join(''); - - tds.push(td); - if(item3.fixed && item3.fixed !== 'right') tds_fixed.push(td); - if(item3.fixed === 'right') tds_fixed_r.push(td); - }); - - trs.push(''+ tds.join('') + ''); - trs_fixed.push(''+ tds_fixed.join('') + ''); - trs_fixed_r.push(''+ tds_fixed_r.join('') + ''); + that.getTrHtml(data, sort, curr, { + trs: trs, + trs_fixed: trs_fixed, + trs_fixed_r: trs_fixed_r }); // 容器的滚动条位置 @@ -1208,9 +1239,9 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ that.renderForm(); // 标注选中行样式 - typeof thisCheckedRowIndex === 'number' && that.setRowChecked({ + typeof that.thisCheckedRowIndex === 'number' && that.setRowChecked({ type: 'radio', - index: thisCheckedRowIndex + index: that.thisCheckedRowIndex }, true); that.syncCheckAll(); diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js new file mode 100644 index 00000000..84273d02 --- /dev/null +++ b/src/modules/treeTable.js @@ -0,0 +1,1035 @@ +/** + * layui.treeTable + * 树表组件 + */ + +layui.define(['table'], function (exports) { + "use strict"; + + var $ = layui.$; + var form = layui.form; + var table = layui.table; + var hint = layui.hint(); + + // api + var treeTable = { + config: {}, + // 事件 + on: table.on, + // 遍历字段 + eachCols: table.eachCols, + index: table.index, + }; + + // 操作当前实例 + var thisTreeTable = function () { + var that = this + , options = that.config + , id = options.id || options.index; + + return { + config: options, + reload: function (options, deep) { + that.reload.call(that, options, deep); + }, + reloadData: function (options, deep) { + treeTable.reloadData(id, options, deep); + } + } + } + + // 获取当前实例 + var getThisTable = function (id) { + var that = thisTreeTable.that[id]; + if (!that) hint.error(id ? ('The treeTable instance with ID \'' + id + '\' not found') : 'ID argument required'); + return that || null; + } + + // 获取当前实例配置项 + var getThisTableConfig = function (id) { + return getThisTable(id).config; + } + + // 字符 + var MOD_NAME = 'treeTable' + , ELEMTREE = '.layui-table-tree' + , THIS = 'layui-this' + , SHOW = 'layui-show' + , HIDE = 'layui-hide' + , HIDE_V = 'layui-hide-v' + , DISABLED = 'layui-disabled' + , NONE = 'layui-none' + + , ELEM_VIEW = '.layui-table-view' + , ELEM_TOOL = '.layui-table-tool' + , ELEM_BOX = '.layui-table-box' + , ELEM_INIT = '.layui-table-init' + , ELEM_HEADER = '.layui-table-header' + , ELEM_BODY = '.layui-table-body' + , ELEM_MAIN = '.layui-table-main' + , ELEM_FIXED = '.layui-table-fixed' + , ELEM_FIXL = '.layui-table-fixed-l' + , ELEM_FIXR = '.layui-table-fixed-r' + , ELEM_TOTAL = '.layui-table-total' + , ELEM_PAGE = '.layui-table-page' + , ELEM_SORT = '.layui-table-sort' + , ELEM_EDIT = 'layui-table-edit' + , ELEM_HOVER = 'layui-table-hover' + , ELEM_GROUP = 'laytable-cell-group' + + var LAY_DATA_INDEX = 'LAY_DATA_INDEX'; + var LAY_DATA_INDEX_HISTORY = 'LAY_DATA_INDEX_HISTORY'; + var LAY_PARENT_INDEX = 'LAY_PARENT_INDEX'; + + // 构造器 + var Class = function (options) { + var that = this; + that.index = ++treeTable.index; + that.config = $.extend(true, {}, that.config, treeTable.config, options); + // 处理一些属性 + that.init(); + that.render(); + }; + + Class.prototype.init = function () { + var that = this; + var options = that.config; + + // 先初始一个空的表格以便拿到对应的表格实例信息 + var tableIns = table.render($.extend({}, options, { + data: [], + url: '', + text: { + none: ' ' + }, + done: null + })) + var id = tableIns.config.id; + thisTreeTable.that[id] = that; // 记录当前实例对象 + that.tableIns = tableIns; + + var treeOptions = options.tree; + var isParentKey = treeOptions.data.key.isParent; + var childrenKey = treeOptions.data.key.children; + + // 处理属性 + var parseData = options.parseData; + var done = options.done; + + if (options.url) { + // 异步加载的时候需要处理parseData进行转换 + options.parseData = function () { + var parseDataThat = this; + var args = arguments; + var retData = args[0]; + if (layui.type(parseData) === 'function') { + retData = parseData.apply(parseDataThat, args) || args[0]; + } + var dataName = parseDataThat.response.dataName; + // 处理simpleData + if (treeOptions.data.simpleData.enable && !treeOptions.async.enable) { // 异步加载和simpleData不应该一起使用 + retData[dataName] = that.flatToTree(retData[dataName]); + } + + that.initData(retData[dataName]); + + return retData; + } + } else { + options.data = options.data || []; + // 处理simpleData + if (treeOptions.data.simpleData.enable) { + options.data = that.flatToTree(options.data); + } + if (options.initSort && options.initSort.type) { + options.data = layui.sort(options.data, options.initSort.field, options.initSort.type === 'desc') + } + that.initData(options.data); + } + + options.done = function () { + var args = arguments; + var doneThat = this; + + var tableView = this.elem.next(); + that.updateStatus(null, { + LAY_HAS_EXPANDED: false // 去除已经打开过的状态 + }) + that.renderTreeTable(tableView); + + if (layui.type(done) === 'function') { + return done.apply(doneThat, args); + } + } + } + + // 初始默认配置 + Class.prototype.config = { + tree: { + view: { + indent: 14, // 层级缩进量 + flexIconClose: '', // 关闭时候的折叠图标 + flexIconOpen: '', // 打开时候的折叠图标 + showIcon: true, // 是否显示图标(节点类型图标) + icon: '', // 节点图标,如果设置了这个属性或者数据中有这个字段信息,不管打开还是关闭都以这个图标的值为准 + iconClose: '', // 打开时候的图标 todo 需要补充一下图标库 + iconOpen: '', // 关闭时候的图标 + iconLeaf: '', // 叶子节点的图标 + showFlexIconIfNotParent: false, // 当节点不是父节点的时候是否显示折叠图标 + dblClickExpand: true, // 双击节点时,是否自动展开父节点的标识 + }, + data: { + key: { + checked: 'LAY_CHECKED', // 节点数据中保存 check 状态的属性名称 + children: "children", // 节点数据中保存子节点数据的属性名称 + isParent: "isParent", // 节点数据保存节点是否为父节点的属性名称 + isHidden: "hidden", // 节点数据保存节点是否隐藏的属性名称 + name: "name", // 节点数据保存节点名称的属性名称 + title: "", // 节点数据保存节点提示信息的属性名称 + url: "url", // 节点数据保存节点链接的目标 URL 的属性名称 + }, + simpleData: { + enable: false, // 是否简单数据模式 + idKey: "id", // 唯一标识的属性名称 + pIdKey: "parentId", + rootPId: null + } + }, + async: { + enable: false, // 是否开启异步加载模式,只有开启的时候其他参数才起作用 + url: '', // 异步加载的接口,可以根据需要设置与顶层接口不同的接口,如果相同可以不设置该参数 + type: null, // 请求的接口类型,设置可缺省同上 + contentType: null, // 提交参数的数据类型,设置可缺省同上 + headers: null, // 设置可缺省同上 + where: null, // 设置可缺省同上 + autoParam: [], // 自动参数 + }, + callback: { + beforeExpand: null, // 展开前的回调 return false 可以阻止展开的动作 + onExpand: null, // 展开之后的回调 + } + } + }; + + Class.prototype.getOptions = function () { + var that = this; + if (that.tableIns) { + return that.tableIns.config + } else { + return that.config; + } + }; + + function flatToTree(flatArr, idKey, pIdKey, childrenKey) { + idKey = idKey || 'id'; + pIdKey = pIdKey || 'parentId'; + childrenKey = childrenKey || 'children'; + // 创建一个空的 nodes 对象,用于保存所有的节点 + var nodes = {}; + // 遍历所有节点,将其加入 nodes 对象中 + layui.each(flatArr, function (index, item) { + nodes[item[idKey]] = $.extend({}, item); + nodes[item[idKey]][childrenKey] = []; + }) + // 遍历所有节点,将其父子关系加入 nodes 对象 + layui.each(nodes, function (index, item) { + if (item[pIdKey] && nodes[item[pIdKey]]) { + nodes[item[pIdKey]][childrenKey].push(item); + } + }) + // 返回顶层节点,即所有节点中 parentId 为 null 的节点 + return Object.values(nodes).filter(function (item) { + return !item[pIdKey]; + }) + } + + Class.prototype.flatToTree = function (tableData) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + + tableData = tableData || table.cache[tableId]; + + return flatToTree(tableData, treeOptions.data.simpleData.idKey, treeOptions.data.simpleData.pIdKey, treeOptions.data.key.children) + } + + Class.prototype.treeToFlat = function (tableData, parentId, parentIndex) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var childrenKey = treeOptions.data.key.children; + var pIdKey = treeOptions.data.simpleData.pIdKey; + + var flat = []; + layui.each(tableData, function (i1, item1) { + var dataIndex = (parentIndex ? parentIndex + '-' : '') + i1; + var dataNew = $.extend({}, item1); + dataNew[childrenKey] = null; + dataNew[pIdKey] = item1[pIdKey] || parentId; + flat.push(dataNew); + flat = flat.concat(that.treeToFlat(item1[childrenKey], item1[treeOptions.data.simpleData.idKey], dataIndex)); + }); + + return flat; + } + + // 通过index获取节点数据 + Class.prototype.getNodeDataByIndex = function (index, clone, newValue) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + + var tableData = table.cache[tableId]; + var indexArr = index.toString().split('-'); + + // var dataRet = tableData[indexArr[0]]; + var dataRet = tableData; + for (var i = 0, childrenKey = treeOptions.data.key.children; i < indexArr.length; i++) { + if (newValue && i === indexArr.length - 1) { + if (newValue === 'delete') { + // 删除 + return (i ? dataRet[childrenKey] : dataRet).splice(indexArr[i], 1)[0]; + } else { + // 更新值 + $.extend((i ? dataRet[childrenKey] : dataRet)[indexArr[i]], newValue); + } + } + dataRet = i ? dataRet[childrenKey][indexArr[i]] : dataRet[indexArr[i]]; + } + return clone ? $.extend({}, dataRet) : dataRet; + } + + treeTable.getNodeDataByIndex = function (id, index) { + var that = getThisTable(id); + return that.getNodeDataByIndex(index, true); + } + + // 判断是否是父节点 + var checkIsParent = function (data, isParentKey, childrenKey) { + isParentKey = isParentKey || 'isParent'; + childrenKey = childrenKey || 'children'; + layui.each(data, function (i1, item1) { + if (!(isParentKey in item1)) { + item1[isParentKey] = !!(item1[childrenKey] && item1[childrenKey].length); + checkIsParent(item1[childrenKey]); + } + }) + } + + Class.prototype.initData = function (data, parentIndex) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + data = data || table.cache[tableId]; + var isParentKey = treeOptions.data.key.isParent; + var childrenKey = treeOptions.data.key.children; + + layui.each(data, function (i1, item1) { + if (!(isParentKey in item1)) { + item1[isParentKey] = !!(item1[childrenKey] && item1[childrenKey].length); + } + item1[LAY_DATA_INDEX_HISTORY] = item1[LAY_DATA_INDEX]; + item1[LAY_PARENT_INDEX] = parentIndex || '' + item1[LAY_DATA_INDEX] = (item1[LAY_PARENT_INDEX] ? item1[LAY_PARENT_INDEX] + '-' : '') + i1; + that.initData(item1[childrenKey] || [], item1[LAY_DATA_INDEX]); + }); + + return data; + } + + var expandNode = function (treeNode, expandFlag, sonSign, focus, callbackFlag) { + // treeNode // 需要展开的节点 + var trElem = treeNode.trElem; + var tableViewElem = trElem.closest(ELEM_VIEW); + var tableViewFilterId = tableViewElem.attr('lay-filter'); + var tableId = tableViewElem.attr('lay-id'); + var tableData = table.cache[tableId]; + var options = table.getOptions(tableId); + var treeOptions = options.tree || {}; + var isParentKey = treeOptions.data.key.isParent; + var trIndex = trElem.attr('data-index'); // 可能出现多层 + var treeTableThat = getThisTable(tableId); + + var trData = treeTableThat.getNodeDataByIndex(trIndex); + + var dataLevel = trElem.data('level'); + var dataLevelNew = (dataLevel || 0) + 1; + + // 后续调优:对已经展开的节点进行展开和已经关闭的节点进行关闭应该做优化减少不必要的代码执行 todo + var isToggle = layui.type(expandFlag) !== 'boolean'; + // var LAY_EXPAND = (layui.type(expandFlag) === 'boolean' ? expandFlag : !trData['LAY_EXPAND']); + var LAY_EXPAND = isToggle ? !trData['LAY_EXPAND'] : expandFlag; + var retValue = trData[isParentKey] ? LAY_EXPAND : null; + + if (callbackFlag && LAY_EXPAND != trData['LAY_EXPAND'] && (!trData['LAY_ASYNC_STATUS'] || trData['LAY_ASYNC_STATUS'] === 'local')) { + var beforeExpand = treeOptions.callback.beforeExpand; + if (layui.type(beforeExpand) === 'function') { + if (beforeExpand(tableId, trData, expandFlag) === false) { + return retValue; + } + } + } + + var LAY_HAS_EXPANDED = trData['LAY_HAS_EXPANDED']; // 展开过,包括异步加载 + + // 找到表格中的同类节点(需要找到data-index一致的所有行) + var trsElem = tableViewElem.find('tr[data-index="' + trIndex + '"]'); + // 处理折叠按钮图标 + var flexIconElem = trsElem.find('.layui-table-tree-flexIcon'); + flexIconElem.html(LAY_EXPAND ? treeOptions.view.flexIconOpen : treeOptions.view.flexIconClose) + trData[isParentKey] && flexIconElem.css('visibility', 'visible'); + // 处理节点图标 + if (treeOptions.view.showIcon && trData[isParentKey] && !trData.icon && !treeOptions.view.icon) { + var nodeIconElem = trsElem.find('.layui-table-tree-nodeIcon'); + nodeIconElem.html(LAY_EXPAND ? treeOptions.view.iconOpen : treeOptions.view.iconClose); + } + + var childNodes = trData[treeOptions.data.key.children] || []; // 测试用后续需要改成子节点的字段名称 + // 处理子节点展示与否 + if (LAY_EXPAND) { + // 展开 + if (LAY_HAS_EXPANDED) { // 已经展开过 + if (LAY_EXPAND == trData['LAY_EXPAND']) { + // 需要更新的状态已经跟节点上的状态一致,则为无效的操作,直接返回避免做一些无意义的操作 + return retValue; + } + trData['LAY_EXPAND'] = LAY_EXPAND; + + tableViewElem.find(childNodes.map(function (value, index, array) { + return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + }).join(',')).removeClass('layui-hide'); + layui.each(childNodes, function (i1, item1) { + if (sonSign && !isToggle) { // 非状态切换的情况下 + // 级联展开子节点 + expandNode({trElem: tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); + } else if (item1.LAY_EXPAND) { + // 级联展开 + expandNode({trElem: tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, true); + } + }) + } else { + var asyncSetting = treeOptions.async || {}; + var asyncUrl = asyncSetting.url || options.url; + if (asyncSetting.enable && asyncUrl && !trData['LAY_ASYNC_STATUS']) { + trData['LAY_ASYNC_STATUS'] = 'loading'; + var params = {}; + // 参数 + var data = $.extend(params, asyncSetting.where || options.where); + var asyncAutoParam = asyncSetting.autoParam; + layui.each(asyncAutoParam, function (index, item) { + var itemStr = item; + var itemArr = item.split('='); + data[itemArr[0].trim()] = trData[(itemArr[1] || itemArr[0]).trim()] + }) + + var asyncContentType = asyncSetting.contentType || options.contentType; + if (asyncContentType && asyncContentType.indexOf("application/json") == 0) { // 提交 json 格式 + data = JSON.stringify(data); + } + var asyncType = asyncSetting.method || options.method; + var asyncDataType = asyncSetting.dataType || options.dataType; + var asyncJsonpCallback = asyncSetting.jsonpCallback || options.jsonpCallback; + var asyncHeaders = asyncSetting.headers || options.headers; + var asyncParseData = asyncSetting.parseData || options.parseData; + var asyncResponse = asyncSetting.response || options.response; + + // that.loading(); + flexIconElem.html('') + $.ajax({ + type: asyncType || 'get' + , url: asyncUrl + , contentType: asyncContentType + , data: data + , dataType: asyncDataType || 'json' + , jsonpCallback: asyncJsonpCallback + , headers: asyncHeaders || {} + , success: function (res) { + trData['LAY_ASYNC_STATUS'] = 'success'; + // 若有数据解析的回调,则获得其返回的数据 + if (typeof asyncParseData === 'function') { + res = asyncParseData.call(options, res) || res; + } + // 检查数据格式是否符合规范 + if (res[asyncResponse.statusName] != asyncResponse.statusCode) { + // 异常处理 todo + } else { + trData[treeOptions.data.key.children] = res[asyncResponse.dataName]; + treeTableThat.initData(trData[treeOptions.data.key.children], trData[LAY_DATA_INDEX]) + // 正常返回 + expandNode(treeNode, true, isToggle ? false : sonSign, focus, callbackFlag); + } + } + , error: function (e, msg) { + trData['LAY_ASYNC_STATUS'] = 'error'; + // 异常处理 todo + typeof options.error === 'function' && options.error(e, msg); + } + }); + return retValue; + } + trData['LAY_EXPAND'] = LAY_EXPAND; + LAY_HAS_EXPANDED = trData['LAY_HAS_EXPANDED'] = true; + if (childNodes.length) { + // 判断是否需要排序 + if (options.initSort && !options.url) { + var initSort = options.initSort; + if (initSort.type) { + childNodes = trData[treeOptions.data.key.children] = layui.sort(childNodes, initSort.field, initSort.type === 'desc'); + } else { + // 恢复默认 + childNodes = trData[treeOptions.data.key.children] = layui.sort(childNodes, table.config.indexName); + } + } + // 将数据通过模板得出节点的html代码 + var str2 = table.getTrHtml(tableId, childNodes, null, null, trIndex); + + var str2Obj = { + trs: $(str2.trs.join('')), + trs_fixed: $(str2.trs_fixed.join('')), + trs_fixed_r: $(str2.trs_fixed_r.join('')) + } + layui.each(childNodes, function (childIndex, childItem) { + str2Obj.trs.eq(childIndex).attr({'data-index': childItem[LAY_DATA_INDEX], 'data-level': dataLevelNew}) + str2Obj.trs_fixed.eq(childIndex).attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew + }) + str2Obj.trs_fixed_r.eq(childIndex).attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew + }) + }) + + tableViewElem.find(ELEM_MAIN).find('tbody tr[data-index="' + trIndex + '"]').after(str2Obj.trs); + tableViewElem.find(ELEM_FIXL).find('tbody tr[data-index="' + trIndex + '"]').after(str2Obj.trs_fixed); + tableViewElem.find(ELEM_FIXR).find('tbody tr[data-index="' + trIndex + '"]').after(str2Obj.trs_fixed_r); + + // 初始化新增的节点中的内容 + layui.each(str2Obj, function (key, item) { + treeTableThat.renderTreeTable(item, dataLevelNew); + }) + + if (sonSign && !isToggle) { // 非状态切换的情况下 + // 级联展开/关闭子节点 + layui.each(childNodes, function (i1, item1) { + expandNode({trElem: tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); + }) + } + } + } + } else { + if (LAY_EXPAND == trData['LAY_EXPAND']) { + // 需要更新的状态已经跟节点上的状态一致,则为无效的操作,直接返回避免做一些无意义的操作 + return retValue; + } + trData['LAY_EXPAND'] = LAY_EXPAND; + // 折叠 + var childNodesFlat = treeTableThat.treeToFlat(childNodes, trData[treeOptions.data.simpleData.idKey], trIndex); + tableViewElem.find(childNodesFlat.map(function (value, index, array) { + if (sonSign && !isToggle) { // 非状态切换的情况下 + treeTableThat.getNodeDataByIndex(value['LAY_DATA_INDEX'])['LAY_EXPAND'] = false; + } + return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + }).join(',')).addClass('layui-hide'); + } + table.resize(tableId); + + if (callbackFlag && trData['LAY_ASYNC_STATUS'] !== 'loading') { + var onExpand = treeOptions.callback.onExpand; + layui.type(onExpand) === 'function' && onExpand(tableId, trData, expandFlag); + } + + return retValue; + } + + treeTable.expandNode = function (id, index, expandFlag, sonSign, callbackFlag) { + var that = getThisTable(id); + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + return expandNode({trElem: tableViewElem.find('tr[data-index="' + index + '"]').first()}, expandFlag, sonSign, null, callbackFlag) + } + + // 目前还有性能问题特别是在data模式需要优化暂时不能使用 todo + treeTable.expandAll = function (id, expandFlag) { + if (layui.type(expandFlag) !== 'boolean') { + return hint.error('expandAll的展开状态参数只接收true/false') + } + layui.each(table.cache[id], function (i1, item1) { + treeTable.expandNode(id, item1['LAY_DATA_INDEX'], expandFlag, true); + }) + } + + Class.prototype.renderTreeTable = function (tableView, level, sonSign) { + var that = this; + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + tableViewElem.addClass('layui-table-tree'); + var tableId = options.id; + var treeOptions = options.tree || {}; + var treeOptionsData = treeOptions.data || {}; + var treeOptionsView = treeOptions.view || {}; + var isParentKey = treeOptionsData.key.isParent; + var tableFilterId = tableViewElem.attr('lay-filter'); + var tableData = table.cache[tableId]; + var treeTableThat = that; + + level = level || 0; + + if (!level) { + // 初始化的表格里面没有level信息,可以作为顶层节点的判断 + tableViewElem.find('.layui-table-body tr').attr('data-level', level); + } + + var dataExpand = {}; // 记录需要展开的数据 + var nameKey = treeOptions.data.key.name; + var indent = treeOptions.view.indent || 14; + // 后期需要添加一个配置来决定展开的图标放在哪个字段 + layui.each(tableView.find('td[data-field="' + nameKey + '"]'), function (index, item) { + item = $(item); + var trElem = item.closest('tr'); + var itemCell = item.children('.layui-table-cell'); + if (itemCell.hasClass('layui-table-tree-item')) { + return; + } + itemCell.addClass('layui-table-tree-item'); + var trIndex = trElem.attr('data-index'); + if (!trIndex) { // 排除在统计行中的节点 + return; + } + var trData = treeTableThat.getNodeDataByIndex(trIndex); + if (trData.LAY_EXPAND) { + // 需要展开 + dataExpand[trIndex] = true; + } + + var tableCellElem = item.find('div.layui-table-cell'); + var htmlTemp = tableCellElem.html(); + + var flexIconElem = item.find('div.layui-table-cell') + .html(['
', + treeOptions.view.flexIconClose, // 折叠图标 + '
', + '
', + treeOptions.view.showIcon ? (trData.icon || treeOptions.view.icon || (trData[isParentKey] ? treeOptions.view.iconClose : treeOptions.view.iconLeaf) || '') : '', + '
', // 区分父子节点 + htmlTemp].join('')) // 图标要可定制 + .find('.layui-table-tree-flexIcon'); + + // 添加展开按钮的事件 + flexIconElem.on('click', function (event) { + layui.stope(event); + // 处理数据 + // var trElem = item.closest('tr'); + expandNode({trElem}, null, null, null, true); + }); + }); + + // 当前层的数据看看是否需要展开 + sonSign !== false && layui.each(dataExpand, function (index, item) { + var trDefaultExpand = tableViewElem.find('tr[data-index="' + index + '"]'); + trDefaultExpand.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconOpen); + expandNode({trElem: trDefaultExpand.first()}, true); + }); + + treeTable.formatNumber(tableId); + form.render(null, tableFilterId); + } + + + /** + * 重新编号 + * @param {String} id 表格id + * @return {Object} layui.treeTable + * */ + treeTable.formatNumber = function (id) { + var that = getThisTable(id); + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + + var num = 0; + layui.each(that.treeToFlat(table.cache[id]), function (i1, item1) { + if (layui.isArray(item1)) { + return; + } + var itemData = that.getNodeDataByIndex(item1.LAY_DATA_INDEX); + itemData['LAY_NUM'] = ++num; + tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"] .laytable-cell-numbers').html(itemData['LAY_NUM']); + }) + return treeTable; + } + + // 树表渲染 + Class.prototype.render = function (type) { + var that = this; + var options = that.config; + if (that.tableIns) { + // 已经在init的时候render一个表格实例了,理论上到这里都必然存在 + // 处理树节点状态 + that.tableIns = table[type === 'reloadData' ? 'reloadData' : 'reload'](that.tableIns.config.id, $.extend(true, {}, options)); + that.config = that.tableIns.config; + } else { + // console.log('真的会进去这个地方吗?2222'); + // var tableIns = table.render(options); + // options = that.config = tableIns.config; + // var id = options.id; + // thisTreeTable.that[id] = that; // 记录当前实例对象 + // that.tableIns = tableIns; // 记录关联的表格实例 + } + }; + + // 表格重载 + Class.prototype.reload = function (options, deep, type) { + var that = this; + + options = options || {}; + delete that.haveInit; + + // 防止数组深度合并 + layui.each(options, function (key, item) { + if (layui.type(item) === 'array') delete that.config[key]; + }); + + // 对参数进行深度或浅扩展 + that.config = $.extend(deep, {}, that.config, options, {autoSort: false}); + + // 执行渲染 + that.render(type); + }; + + // 仅重载数据 + treeTable.reloadData = function () { + var args = $.extend(true, [], arguments); + args[3] = 'reloadData'; + + return treeTable.reload.apply(null, args); + }; + + var updateStatus = function (data, statusObj, childrenKey) { + layui.each(data, function (i1, item1) { + if (layui.type(statusObj) === 'function') { + statusObj(item1); + } else { + $.extend(item1, statusObj); + } + updateStatus(item1[childrenKey], statusObj, childrenKey); + }) + } + + Class.prototype.updateStatus = function (data, statusObj) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + data = data || table.cache[options.id]; + + return updateStatus(data, statusObj, treeOptions.data.key.children); + } + + treeTable.updateStatus = function (id, statusObj, data) { + var that = getThisTable(id); + var options = that.getOptions(); + if (!data) { + if (options.url) { + data = table.cache[options.id]; + } else { + data = options.data; + } + } + that.updateStatus(data, statusObj); + return options; + } + + treeTable.sort = function (id) { + var that = getThisTable(id); + var options = that.getOptions(); + var initSort = options.initSort; + + if (!options.url) { + if (initSort.type) { + options.data = layui.sort(options.data, initSort.field, initSort.type === 'desc'); + } else { + options.data = layui.sort(options.data, table.config.indexName); + } + treeTable.reloadData(id); + } else { + // url异步取数的表格一般需要自己添加监听之后进行reloadData并且把排序参数加入到where中 + } + } + + // 处理事件 + var updateObjParams = function (obj) { + var tableId = obj.config.id; + var tableThat = getThisTable(tableId); + var trData = obj.data = treeTable.getNodeDataByIndex(tableId, obj.index); // 克隆的 + var trIndex = trData[LAY_DATA_INDEX]; + + // 处理update方法 + var updateFn = obj.update; + obj.update = function () { + var updateThat = this; + var args = arguments; + $.extend(tableThat.getNodeDataByIndex(trIndex), args[0]); + var ret = updateFn.apply(updateThat, args); // 主要负责更新节点内容 + tableThat.renderTreeTable(obj.tr, obj.tr.attr('data-level'), false); + return ret; + } + + // 处理del方法 + var delFn = obj.del; + obj.del = function () { + var updateThat = this; + var args = arguments; + // 原始的方法是讲对应下标的元素换成空数组,并删除相关节点,已经由 + // var ret = delFn.apply(updateThat, args); + // delete table.cache[tableId][trIndex]; + treeTable.removeNode(tableId, trIndex); + // return ret; + } + + } + + // 更新数据 + treeTable.updateNode = function (id, index, newNode) { + var that = getThisTable(id); + var options = that.getOptions(); + var treeOptions = options.tree; + var tableView = options.elem.next(); + var trLevel = tableView.find('tr[data-index="' + index + '"]').attr('data-level') + + if (!newNode) { + return; + } + // 更新值 + var newNodeTemp = that.getNodeDataByIndex(index, false, newNode); + // 获取新的tr替换 + var trNew = table.getTrHtml(id, [newNodeTemp]); + // 重新渲染tr + layui.each(['main', 'fixed-l', 'fixed-r'], function (i, item) { + tableView.find('.layui-table-' + item + ' tbody tr[data-index="' + index + '"]').replaceWith($(trNew[['trs', 'trs_fixed', 'trs_fixed_r'][i]].join('')).attr('data-index', index)); + }); + that.renderTreeTable(tableView.find('tr[data-index="' + index + '"]'), trLevel); + } + + // 删除数据 + treeTable.removeNode = function (id, index) { + var that = getThisTable(id); + var options = that.getOptions(); + var treeOptions = options.tree; + var tableView = options.elem.next(); + if (!layui.isArray(index)) { + index = [index]; + } + var delNode; + var indexArr = []; + layui.each(index, function (index, indexValue) { + delNode = that.getNodeDataByIndex(indexValue, false, 'delete'); + var delNodesFlat = that.treeToFlat([delNode], delNode[treeOptions.data.simpleData.pIdKey], delNode[LAY_PARENT_INDEX]); + layui.each(delNodesFlat, function (i2, item2) { + indexArr.push('tr[data-index="' + item2[LAY_DATA_INDEX] + '"]'); + }) + }); + + tableView.find(indexArr.join(',')).remove(); // 删除行 + // 重新整理数据 + var tableData = that.initData(); + // index发生变化需要更新页面tr中对应的data-index 新增和删除都要注意数据结构变动之后的index问题 + layui.each(that.treeToFlat(tableData), function (i3, item3) { + if (item3[LAY_DATA_INDEX_HISTORY] && item3[LAY_DATA_INDEX_HISTORY] !== item3[LAY_DATA_INDEX]) { + tableView.find('tr[data-index="' + item3[LAY_DATA_INDEX_HISTORY] + '"]').attr('data-index', item3[LAY_DATA_INDEX]); + item3[LAY_DATA_INDEX_HISTORY] = item3[LAY_DATA_INDEX]; + } + }); + treeTable.formatNumber(id); + } + + /** + * 新增数据节点 + * @param {String} id 树表id + * @param {String|Number} parentIndex 指定的父节点,如果增加根节点,请设置 parentIndex 为 null 即可 + * @param {Number} index:Number 新节点插入的位置(从 0 开始)index = -1(默认) 时,插入到最后 + * @param {Object|Array} newNodes 新增的节点,单个或者多个 + * @return {Array} 新增的节点 + * */ + treeTable.addNodes = function (id, parentIndex, index, newNodes) { + var that = getThisTable(id); + var options = that.getOptions(); + var treeOptions = options.tree; + var tableViewElem = options.elem.next(); + + parentIndex = layui.type(parentIndex) === 'number' ? parentIndex.toString() : parentIndex; + var parentNode = parentIndex ? that.getNodeDataByIndex(parentIndex) : null; + index = layui.type(index) === 'number' ? index : -1; + + // 添加数据 + newNodes = $.extend(true, [], (layui.isArray(newNodes) ? newNodes : [newNodes])); + + var tableData, dataAfter; + if (!parentNode) { + // 添加到根节点 + dataAfter = table.cache[id].splice(index === -1 ? table.cache[id].length : index); + table.cache[id] = table.cache[id].concat(newNodes, dataAfter); + // 将新节点添加到页面 + tableData = that.initData(); + + var newNodesHtml = table.getTrHtml(id, newNodes); + var newNodesHtmlObj = { + trs: $(newNodesHtml.trs.join('')), + trs_fixed: $(newNodesHtml.trs_fixed.join('')), + trs_fixed_r: $(newNodesHtml.trs_fixed_r.join('')) + } + + layui.each(newNodes, function (newNodeIndex, newNodeItem) { + newNodesHtmlObj.trs.eq(newNodeIndex).attr({'data-index': newNodeItem[LAY_DATA_INDEX], 'data-level': '0'}) + newNodesHtmlObj.trs_fixed.eq(newNodeIndex).attr({ + 'data-index': newNodeItem[LAY_DATA_INDEX], + 'data-level': '0' + }) + newNodesHtmlObj.trs_fixed_r.eq(newNodeIndex).attr({ + 'data-index': newNodeItem[LAY_DATA_INDEX], + 'data-level': '0' + }) + }) + + var trIndexPrev = parseInt(newNodes[0][LAY_DATA_INDEX]) - 1; + var tableViewElemMAIN = tableViewElem.find(ELEM_MAIN); + var tableViewElemFIXL = tableViewElem.find(ELEM_FIXL); + var tableViewElemFIXR = tableViewElem.find(ELEM_FIXR); + if (trIndexPrev === -1) { + tableViewElemMAIN.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs_fixed_r); + } else { + tableViewElemMAIN.find('tr[data-level="0"][data-index="' + trIndexPrev + '"]').after(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tr[data-level="0"][data-index="' + trIndexPrev + '"]').after(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tr[data-level="0"][data-index="' + trIndexPrev + '"]').after(newNodesHtmlObj.trs_fixed_r); + } + + // 更新编号 + layui.each(tableData, function (i1, item1) { + tableViewElemMAIN.find('tr[data-level="0"]').eq(i1).attr('data-index', i1); + tableViewElemFIXL.find('tr[data-level="0"]').eq(i1).attr('data-index', i1); + tableViewElemFIXR.find('tr[data-level="0"]').eq(i1).attr('data-index', i1); + }) + that.renderTreeTable(tableViewElem.find(newNodes.map(function (value, index, array) { + return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + }).join(','))); + } else { + var isParentKey = treeOptions.data.key.isParent; + var childKey = treeOptions.data.key.children; + + parentNode[isParentKey] = true; + var childrenNodes = parentNode[childKey]; + if (!childrenNodes) { + childrenNodes = parentNode[childKey] = newNodes; + } else { + dataAfter = childrenNodes.splice(index === -1 ? childrenNodes.length : index); + childrenNodes = parentNode[childKey] = childrenNodes.concat(newNodes, dataAfter); + } + // 删除已经存在的同级节点以及他们的子节点,并且把中间节点的已展开过的状态设置为false + that.updateStatus(childrenNodes, function (d) { + if (d[isParentKey]) { + d['LAY_HAS_EXPANDED'] = false; + } + }); + var childrenNodesFlat = that.treeToFlat(childrenNodes); + tableViewElem.find(childrenNodesFlat.map(function (value) { + return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + }).join(',')).remove(); + + tableData = that.initData(); + // 去掉父节点的已经展开过的状态,重新执行一次展开的方法 + parentNode['LAY_HAS_EXPANDED'] = false; + parentNode['LAY_ASYNC_STATUS'] = 'local'; // 转为本地数据,应该规定异步加载子节点的时候addNodes的规则 + expandNode({trElem: tableViewElem.find('tr[data-index="' + parentIndex + '"]')}, true) + } + return newNodes; + } + + // 排序之后重新渲染成树表 + treeTable.on('sort', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + + if (tableView.hasClass('layui-table-tree')) { + treeTable.sort(tableId); + } + }); + + // 行点击 + treeTable.on('row', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + + if (tableView.hasClass('layui-table-tree')) { + updateObjParams(obj); + } + }) + + // 行双击 + treeTable.on('rowDouble', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + + if (tableView.hasClass('layui-table-tree')) { + updateObjParams(obj); + + var treeOptions = options.tree || {}; + if (treeOptions.view.dblClickExpand) { + expandNode({trElem: obj.tr.first()}, null, null, null, true); + } + } + }) + + // 带lay-event节点点击 + treeTable.on('tool', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + + if (tableView.hasClass('layui-table-tree')) { + updateObjParams(obj); + } + }) + + /** + * 获得数据 + * @param {String} id 表格id + * @param {Boolean} simpleData 是否返回平铺结构的数据 + * @return {Array} 表格数据 + * */ + treeTable.getData = function (id, simpleData) { + var tableData = $.extend(true, [], table.cache[id] || []); + return simpleData ? getThisTable(id).treeToFlat(tableData) : tableData; + } + + //记录所有实例 + thisTreeTable.that = {}; //记录所有实例对象 + // thisTreeTable.config = {}; //记录所有实例配置项 + + // 重载 + treeTable.reload = function (id, options, deep, type) { + var config = getThisTableConfig(id); //获取当前实例配置项 + if (!config) return; + + var that = getThisTable(id); + that.reload(options, deep, type); + + return thisTreeTable.call(that); + }; + + // 核心入口 + treeTable.render = function (options) { + var inst = new Class(options); + return thisTreeTable.call(inst); + }; + + exports(MOD_NAME, treeTable); +}); \ No newline at end of file From 5b20931196ce1ca28fb2ca1683e112b1c07f2cc1 Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <470459819@qq.com> Date: Fri, 7 Apr 2023 16:39:17 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=91=E8=A1=A8?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=9A=84=E4=B8=80=E4=BA=9B=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=EF=BC=9B=E8=B0=83=E6=95=B4table.getOptions?= =?UTF-8?q?=E7=9A=84=E8=BF=94=E5=9B=9E=EF=BC=8C=E4=B8=8D=E5=81=9A=E5=85=8B?= =?UTF-8?q?=E9=9A=86=E7=9B=B4=E6=8E=A5=E8=BF=94=E5=9B=9E=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E5=AE=9E=E4=BE=8B=E7=9A=84=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=EF=BC=9B=E4=BC=98=E5=8C=96table.reloadData=E7=BB=86=E8=8A=82?= =?UTF-8?q?=EF=BC=8C=E5=B0=86=E4=BB=A5=E5=89=8D=E5=8F=AA=E5=85=81=E8=AE=B8?= =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8F=82=E6=95=B0=E6=94=B9=E6=88=90=E6=8E=92?= =?UTF-8?q?=E9=99=A4=E8=87=AA=E5=B8=A6=E5=8F=82=E6=95=B0=E4=B8=AD=E4=BC=9A?= =?UTF-8?q?=E5=BD=B1=E5=93=8D=E6=95=B4=E4=BD=93=E4=B8=8D=E9=80=82=E5=90=88?= =?UTF-8?q?=E4=BD=9C=E4=B8=BA=E9=87=8D=E8=BD=BD=E6=95=B0=E6=8D=AE=E7=9A=84?= =?UTF-8?q?=E5=8F=82=E6=95=B0=EF=BC=8C=E8=BF=99=E6=A0=B7=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD=E5=AF=B9=E4=BA=8E=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E8=87=AA=E5=AE=9A=E4=B9=89=E5=B1=9E=E6=80=A7=E7=9A=84?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=EF=BC=8C=E5=9B=A0=E4=B8=BA=E8=BF=99=E7=B1=BB?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E4=B8=80=E6=A0=B7=E4=B8=8D=E4=BC=9A=E5=BD=B1?= =?UTF-8?q?=E5=93=8D=E5=88=B0=E5=AE=9E=E4=BE=8B=E7=9A=84=E6=9C=AC=E8=B4=A8?= =?UTF-8?q?=EF=BC=8C=E5=8F=AF=E4=BB=A5=E6=A0=B9=E6=8D=AE=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E4=BF=AE=E6=94=B9=EF=BC=9B=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?treeTable=E7=9A=84=E4=B8=80=E4=BA=9B=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/layui.css | 4 ++++ src/modules/table.js | 16 +++++++--------- src/modules/treeTable.js | 40 +++++++++++++++++++++------------------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/css/layui.css b/src/css/layui.css index 78ea7bb7..65f94898 100644 --- a/src/css/layui.css +++ b/src/css/layui.css @@ -1099,6 +1099,10 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh .layui-table-tips-c:hover{background-color: #777;} .layui-table-tips-c:before{position: relative; right: -2px;} +/** 树表 **/ +.layui-table-tree-nodeIcon {padding-right: 2px;width: 20px;} +.layui-table-tree-nodeIcon > * {width: 100%;} + /** 文件上传 **/ .layui-upload-file{display: none!important; opacity: .01; filter: Alpha(opacity=1);} .layui-upload-list{margin: 10px 0;} diff --git a/src/modules/table.js b/src/modules/table.js index 9a764eaf..415f988d 100644 --- a/src/modules/table.js +++ b/src/modules/table.js @@ -2722,7 +2722,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ // 获取表格配置信息 table.getOptions = function (id) { - return $.extend(true, {}, getThisTableConfig(id)); + return getThisTableConfig(id); } // 显示或隐藏列 @@ -2789,22 +2789,20 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ var args = $.extend([], arguments); args[3] = 'reloadData'; - // 重载时,与数据相关的参数 + // 重载时,影响整个结构的参数,不适合更新的参数 var dataParams = new RegExp('^('+ [ - 'data', 'url', 'method', 'contentType', - 'dataType','jsonpCallback', - 'headers', 'where', 'page', 'limit', - 'request', 'response', 'parseData', - 'scrollPos' + 'elem', 'id', 'cols', 'width', 'height', 'maxHeight', + 'toolbar', 'defaultToolbar', + 'className', 'css', 'totalRow', 'page', 'pagebar' ].join('|') + ')$'); // 过滤与数据无关的参数 layui.each(args[1], function (key, value) { - if(!dataParams.test(key)){ + if(dataParams.test(key)){ delete args[1][key]; } }); - + return table.reload.apply(null, args); }; diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index 84273d02..67e82821 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -99,9 +99,6 @@ layui.define(['table'], function (exports) { var tableIns = table.render($.extend({}, options, { data: [], url: '', - text: { - none: ' ' - }, done: null })) var id = tableIns.config.id; @@ -208,13 +205,14 @@ layui.define(['table'], function (exports) { beforeExpand: null, // 展开前的回调 return false 可以阻止展开的动作 onExpand: null, // 展开之后的回调 } - } + }, + autoSort: false }; Class.prototype.getOptions = function () { var that = this; if (that.tableIns) { - return that.tableIns.config + return table.getOptions(that.tableIns.config.id); // 获取表格的实时配置信息 } else { return that.config; } @@ -392,9 +390,7 @@ layui.define(['table'], function (exports) { if (LAY_EXPAND) { // 展开 if (LAY_HAS_EXPANDED) { // 已经展开过 - if (LAY_EXPAND == trData['LAY_EXPAND']) { - // 需要更新的状态已经跟节点上的状态一致,则为无效的操作,直接返回避免做一些无意义的操作 - return retValue; + if (LAY_EXPAND == trData['LAY_EXPAND']) { // 已经和当前的状态一样,是否有优化的空间,要注意直接方法调用级联展开和触发和不是级联的情况下的区别 } trData['LAY_EXPAND'] = LAY_EXPAND; @@ -521,19 +517,23 @@ layui.define(['table'], function (exports) { } } } else { - if (LAY_EXPAND == trData['LAY_EXPAND']) { - // 需要更新的状态已经跟节点上的状态一致,则为无效的操作,直接返回避免做一些无意义的操作 - return retValue; - } + if (LAY_EXPAND == trData['LAY_EXPAND']) {} trData['LAY_EXPAND'] = LAY_EXPAND; // 折叠 - var childNodesFlat = treeTableThat.treeToFlat(childNodes, trData[treeOptions.data.simpleData.idKey], trIndex); - tableViewElem.find(childNodesFlat.map(function (value, index, array) { - if (sonSign && !isToggle) { // 非状态切换的情况下 - treeTableThat.getNodeDataByIndex(value['LAY_DATA_INDEX'])['LAY_EXPAND'] = false; - } - return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' - }).join(',')).addClass('layui-hide'); + if (sonSign && !isToggle) { // 非状态切换的情况下 + layui.each(childNodes, function (i1, item1) { + expandNode({trElem: tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); + }); + tableViewElem.find(childNodes.map(function (value, index, array) { // 只隐藏直接子节点,其他由递归的处理 + return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + }).join(',')).addClass('layui-hide'); + } else { + var childNodesFlat = treeTableThat.treeToFlat(childNodes, trData[treeOptions.data.simpleData.idKey], trIndex); + tableViewElem.find(childNodesFlat.map(function (value, index, array) { + return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + }).join(',')).addClass('layui-hide'); + } + } table.resize(tableId); @@ -756,6 +756,7 @@ layui.define(['table'], function (exports) { } else { options.data = layui.sort(options.data, table.config.indexName); } + that.initData(options.data); treeTable.reloadData(id); } else { // url异步取数的表格一般需要自己添加监听之后进行reloadData并且把排序参数加入到where中 @@ -1016,6 +1017,7 @@ layui.define(['table'], function (exports) { // 重载 treeTable.reload = function (id, options, deep, type) { + deep = deep !== false; // 默认采用深拷贝 var config = getThisTableConfig(id); //获取当前实例配置项 if (!config) return; From 9044647dc20748d3986006fbab68524925af9e6f Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Mon, 10 Apr 2023 15:55:55 +0800 Subject: [PATCH 06/15] =?UTF-8?q?table=E4=BF=AE=E5=A4=8D=E5=A4=9A=E7=BA=A7?= =?UTF-8?q?=E8=A1=A8=E5=A4=B4=E5=AD=98=E5=9C=A8=E8=87=AA=E5=8A=A8=E5=88=86?= =?UTF-8?q?=E9=85=8D=E5=AE=BD=E5=BA=A6=E5=88=97=E7=9A=84=E6=97=B6=E5=80=99?= =?UTF-8?q?=E5=9C=A8=E6=9F=90=E4=BA=9B=E5=9C=BA=E6=99=AF=E4=B8=8B=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E5=8D=A0=E6=BB=A1=E8=A1=A8=E6=A0=BC=E5=AE=B9=E5=99=A8?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=9BtreeTable=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?set=E6=96=B9=E6=B3=95=E7=94=A8=E4=BA=8E=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=85=A8=E5=B1=80=E9=BB=98=E8=AE=A4=E5=B1=9E=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/table.js | 23 +++++++++++++---------- src/modules/treeTable.js | 7 ++++++- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/modules/table.js b/src/modules/table.js index e0e1e902..7782bef6 100644 --- a/src/modules/table.js +++ b/src/modules/table.js @@ -811,13 +811,20 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ if(that.autoColNums > 0 && patchNums >= -colNums && patchNums <= colNums){ var getEndTh = function(th){ - var field; - th = th || that.layHeader.eq(0).find('thead > tr:first-child > th:last-child') - field = th.data('field'); + var field, thRet; + th = th || that.layHeader.eq(0).find('thead th:last-child') + layui.each(th, function (thIndex, thElem) { + thElem = $(thElem); + if (!thElem.children('.'+ELEM_GROUP).length) { // 排除合并表头 + field = thElem.attr('data-field'); + thRet = thElem; + } + }) + if(!field && th.prev()[0]){ return getEndTh(th.prev()) } - return th + return thRet }; var th = getEndTh(); var key = th.data('key'); @@ -897,6 +904,8 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ table.cache[that.key] = []; //格式化缓存数据 that.syncCheckAll(); + that.renderForm(); + that.setColsWidth(); }; // 初始页码 @@ -957,7 +966,6 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ } // 检查数据格式是否符合规范 if(res[response.statusName] != response.statusCode){ - that.renderForm(); that.errorView( res[response.msgName] || ('返回的数据不符合规范,正确的成功状态码应为:"'+ response.statusName +'": '+ response.statusCode) @@ -980,10 +988,6 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ } ,error: function(e, msg){ that.errorView('请求异常,错误提示:'+ msg); - - that.renderForm(); - that.setColsWidth(); - typeof options.error === 'function' && options.error(e, msg); } }); @@ -1269,7 +1273,6 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ //如果无数据 if(data.length === 0){ - that.renderForm(); return that.errorView(options.text.none); } else { that.layFixLeft.removeClass(HIDE); diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index 67e82821..5a1db61a 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -19,6 +19,11 @@ layui.define(['table'], function (exports) { // 遍历字段 eachCols: table.eachCols, index: table.index, + set: function(options){ + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, }; // 操作当前实例 @@ -1034,4 +1039,4 @@ layui.define(['table'], function (exports) { }; exports(MOD_NAME, treeTable); -}); \ No newline at end of file +}); From 1fd73f432924931b7c169cb05ec783a10e3ae0ab Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Tue, 11 Apr 2023 15:13:54 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8DtreeTable=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/treeTable.js | 75 +++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index 5a1db61a..b2550a83 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -284,15 +284,22 @@ layui.define(['table'], function (exports) { var treeOptions = options.tree; var tableId = options.id; - var tableData = table.cache[tableId]; - var indexArr = index.toString().split('-'); + var tableData = that.getTableData(); + index += ''; + var indexArr = index.split('-'); - // var dataRet = tableData[indexArr[0]]; var dataRet = tableData; + var tableCache = (options.url || indexArr.length > 1) ? null : table.cache[tableId]; // 只有在删除根节点的时候才需要处理 for (var i = 0, childrenKey = treeOptions.data.key.children; i < indexArr.length; i++) { if (newValue && i === indexArr.length - 1) { if (newValue === 'delete') { // 删除 + if (tableCache) { + // 同步cache + tableCache.splice(tableCache.findIndex(function (value) { + return value[LAY_DATA_INDEX] === index; + }), 1) + } return (i ? dataRet[childrenKey] : dataRet).splice(indexArr[i], 1)[0]; } else { // 更新值 @@ -326,7 +333,7 @@ layui.define(['table'], function (exports) { var options = that.getOptions(); var treeOptions = options.tree; var tableId = options.id; - data = data || table.cache[tableId]; + data = data || that.getTableData(); var isParentKey = treeOptions.data.key.isParent; var childrenKey = treeOptions.data.key.children; @@ -349,12 +356,12 @@ layui.define(['table'], function (exports) { var tableViewElem = trElem.closest(ELEM_VIEW); var tableViewFilterId = tableViewElem.attr('lay-filter'); var tableId = tableViewElem.attr('lay-id'); - var tableData = table.cache[tableId]; var options = table.getOptions(tableId); var treeOptions = options.tree || {}; var isParentKey = treeOptions.data.key.isParent; var trIndex = trElem.attr('data-index'); // 可能出现多层 var treeTableThat = getThisTable(tableId); + var tableData = treeTableThat.getTableData(); var trData = treeTableThat.getNodeDataByIndex(trIndex); @@ -414,6 +421,7 @@ layui.define(['table'], function (exports) { } else { var asyncSetting = treeOptions.async || {}; var asyncUrl = asyncSetting.url || options.url; + // 提供一个能支持用户在获取子数据转换调用的回调,这样让子节点数据获取更加灵活 todo if (asyncSetting.enable && asyncUrl && !trData['LAY_ASYNC_STATUS']) { trData['LAY_ASYNC_STATUS'] = 'loading'; var params = {}; @@ -455,7 +463,10 @@ layui.define(['table'], function (exports) { } // 检查数据格式是否符合规范 if (res[asyncResponse.statusName] != asyncResponse.statusCode) { + trData['LAY_ASYNC_STATUS'] = 'error'; // 异常处理 todo + flexIconElem.html(''); + // 事件 } else { trData[treeOptions.data.key.children] = res[asyncResponse.dataName]; treeTableThat.initData(trData[treeOptions.data.key.children], trData[LAY_DATA_INDEX]) @@ -484,6 +495,7 @@ layui.define(['table'], function (exports) { childNodes = trData[treeOptions.data.key.children] = layui.sort(childNodes, table.config.indexName); } } + treeTableThat.initData(trData[treeOptions.data.key.children], trData[LAY_DATA_INDEX]); // 将数据通过模板得出节点的html代码 var str2 = table.getTrHtml(tableId, childNodes, null, null, trIndex); @@ -578,14 +590,19 @@ layui.define(['table'], function (exports) { var treeOptionsView = treeOptions.view || {}; var isParentKey = treeOptionsData.key.isParent; var tableFilterId = tableViewElem.attr('lay-filter'); - var tableData = table.cache[tableId]; var treeTableThat = that; + // var tableData = treeTableThat.getTableData(); level = level || 0; if (!level) { // 初始化的表格里面没有level信息,可以作为顶层节点的判断 - tableViewElem.find('.layui-table-body tr').attr('data-level', level); + tableViewElem.find('.layui-table-body tr:not([data-level])').attr('data-level', level); + layui.each(table.cache[tableId], function (dataIndex, dataItem) { + tableViewElem.find('.layui-table-main tbody tr[data-level="0"]:eq('+dataIndex+')').attr('data-index', dataItem[LAY_DATA_INDEX]); + tableViewElem.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq('+dataIndex+')').attr('data-index', dataItem[LAY_DATA_INDEX]); + tableViewElem.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq('+dataIndex+')').attr('data-index', dataItem[LAY_DATA_INDEX]); + }) } var dataExpand = {}; // 记录需要展开的数据 @@ -736,6 +753,12 @@ layui.define(['table'], function (exports) { return updateStatus(data, statusObj, treeOptions.data.key.children); } + Class.prototype.getTableData = function () { + var that = this; + var options = that.getOptions(); + return options.url ? table.cache[options.id] : options.data; + } + treeTable.updateStatus = function (id, statusObj, data) { var that = getThisTable(id); var options = that.getOptions(); @@ -875,11 +898,20 @@ layui.define(['table'], function (exports) { // 添加数据 newNodes = $.extend(true, [], (layui.isArray(newNodes) ? newNodes : [newNodes])); - var tableData, dataAfter; + var tableData = that.getTableData(), dataAfter; if (!parentNode) { // 添加到根节点 dataAfter = table.cache[id].splice(index === -1 ? table.cache[id].length : index); table.cache[id] = table.cache[id].concat(newNodes, dataAfter); + if (!options.url) { + // 静态data模式 + if (!options.page) { + options.data = table.cache[id]; + } else { + var pageOptions = options.page; + options.data.splice.apply(options.data, [pageOptions.limit * (pageOptions.curr - 1), pageOptions.limit].concat(table.cache[id])) + } + } // 将新节点添加到页面 tableData = that.initData(); @@ -901,27 +933,36 @@ layui.define(['table'], function (exports) { 'data-level': '0' }) }) - var trIndexPrev = parseInt(newNodes[0][LAY_DATA_INDEX]) - 1; var tableViewElemMAIN = tableViewElem.find(ELEM_MAIN); var tableViewElemFIXL = tableViewElem.find(ELEM_FIXL); var tableViewElemFIXR = tableViewElem.find(ELEM_FIXR); if (trIndexPrev === -1) { + // 插入到开头 tableViewElemMAIN.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs); tableViewElemFIXL.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs_fixed); tableViewElemFIXR.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs_fixed_r); } else { - tableViewElemMAIN.find('tr[data-level="0"][data-index="' + trIndexPrev + '"]').after(newNodesHtmlObj.trs); - tableViewElemFIXL.find('tr[data-level="0"][data-index="' + trIndexPrev + '"]').after(newNodesHtmlObj.trs_fixed); - tableViewElemFIXR.find('tr[data-level="0"][data-index="' + trIndexPrev + '"]').after(newNodesHtmlObj.trs_fixed_r); + if (index === -1) { + // 追加到最后 + tableViewElemMAIN.find('tbody').append(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tbody').append(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tbody').append(newNodesHtmlObj.trs_fixed_r); + } else { + var trIndexNext = dataAfter[0][LAY_DATA_INDEX_HISTORY]; + tableViewElemMAIN.find('tr[data-level="0"][data-index="' + trIndexNext + '"]').before(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tr[data-level="0"][data-index="' + trIndexNext + '"]').before(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tr[data-level="0"][data-index="' + trIndexNext + '"]').before(newNodesHtmlObj.trs_fixed_r); + } + } // 更新编号 - layui.each(tableData, function (i1, item1) { - tableViewElemMAIN.find('tr[data-level="0"]').eq(i1).attr('data-index', i1); - tableViewElemFIXL.find('tr[data-level="0"]').eq(i1).attr('data-index', i1); - tableViewElemFIXR.find('tr[data-level="0"]').eq(i1).attr('data-index', i1); - }) + // layui.each(tableData, function (i1, item1) { + // tableViewElemMAIN.find('tr[data-level="0"]').eq(i1).attr('data-index', item1[LAY_DATA_INDEX]); + // tableViewElemFIXL.find('tr[data-level="0"]').eq(i1).attr('data-index', item1[LAY_DATA_INDEX]); + // tableViewElemFIXR.find('tr[data-level="0"]').eq(i1).attr('data-index', item1[LAY_DATA_INDEX]); + // }) that.renderTreeTable(tableViewElem.find(newNodes.map(function (value, index, array) { return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(','))); From 8891ef910f2b9ce6ca307a8c2c7286d36c054d6c Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Wed, 12 Apr 2023 17:15:51 +0800 Subject: [PATCH 08/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8DtreeTable=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/treeTable.js | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index b2550a83..d676b0a7 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -174,7 +174,7 @@ layui.define(['table'], function (exports) { flexIconOpen: '', // 打开时候的折叠图标 showIcon: true, // 是否显示图标(节点类型图标) icon: '', // 节点图标,如果设置了这个属性或者数据中有这个字段信息,不管打开还是关闭都以这个图标的值为准 - iconClose: '', // 打开时候的图标 todo 需要补充一下图标库 + iconClose: '', // 打开时候的图标 iconOpen: '', // 关闭时候的图标 iconLeaf: '', // 叶子节点的图标 showFlexIconIfNotParent: false, // 当节点不是父节点的时候是否显示折叠图标 @@ -284,6 +284,11 @@ layui.define(['table'], function (exports) { var treeOptions = options.tree; var tableId = options.id; + var dataCache = table.cache[tableId][index]; + if (newValue !== 'delete' && dataCache) { + return clone ? $.extend({}, dataCache) : dataCache; + } + var tableData = that.getTableData(); index += ''; var indexArr = index.split('-'); @@ -342,9 +347,10 @@ layui.define(['table'], function (exports) { item1[isParentKey] = !!(item1[childrenKey] && item1[childrenKey].length); } item1[LAY_DATA_INDEX_HISTORY] = item1[LAY_DATA_INDEX]; - item1[LAY_PARENT_INDEX] = parentIndex || '' - item1[LAY_DATA_INDEX] = (item1[LAY_PARENT_INDEX] ? item1[LAY_PARENT_INDEX] + '-' : '') + i1; - that.initData(item1[childrenKey] || [], item1[LAY_DATA_INDEX]); + item1[LAY_PARENT_INDEX] = parentIndex = parentIndex || ''; + var dataIndex = item1[LAY_DATA_INDEX] = (parentIndex ? parentIndex + '-' : '') + i1; + dataIndex.indexOf('-') !== -1 && (table.cache[tableId][dataIndex] = item1); + that.initData(item1[childrenKey] || [], dataIndex); }); return data; @@ -1035,7 +1041,7 @@ layui.define(['table'], function (exports) { } }) - // 带lay-event节点点击 + // tr中带lay-event节点点击 treeTable.on('tool', function (obj) { var options = obj.config; var tableView = options.elem.next(); @@ -1046,6 +1052,23 @@ layui.define(['table'], function (exports) { } }) + // 行内编辑 + treeTable.on('edit', function (obj) { + // 如果编辑涉及到关键的name字段需要重新更新一下tr节点 + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + + if (tableView.hasClass('layui-table-tree')) { + updateObjParams(obj); + if (obj.field === options.tree.data.key.name) { + obj.tr.find('td[data-field="'+obj.field+'"]').children('div.layui-table-cell').removeClass('layui-table-tree-item') + obj.update({}); // 通过update调用执行tr节点的更新 + } + } + }); + + /** * 获得数据 * @param {String} id 表格id @@ -1053,7 +1076,11 @@ layui.define(['table'], function (exports) { * @return {Array} 表格数据 * */ treeTable.getData = function (id, simpleData) { - var tableData = $.extend(true, [], table.cache[id] || []); + var tableData = []; + layui.each($.extend(true, [], table.cache[id] || []), function (index, item) { + // 遍历排除掉临时的数据 + tableData.push(item); + }) return simpleData ? getThisTable(id).treeToFlat(tableData) : tableData; } From 598360d7a96c0473eb0de85d22ffd22270aff09e Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Thu, 13 Apr 2023 18:29:23 +0800 Subject: [PATCH 09/15] =?UTF-8?q?treeTable=E6=96=B0=E5=A2=9E=E5=A4=8D?= =?UTF-8?q?=E9=80=89=E6=A1=86=E5=92=8C=E5=8D=95=E9=80=89=E6=A1=86=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BB=A5=E5=8F=8A=E9=80=9A=E8=BF=87checkStat?= =?UTF-8?q?us=E8=8E=B7=E5=8F=96=E9=80=89=E4=B8=AD=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E7=AD=89=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/treeTable.js | 156 +++++++++++++++++++++++++++++++++------ 1 file changed, 132 insertions(+), 24 deletions(-) diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index d676b0a7..ff5c56d9 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -19,7 +19,7 @@ layui.define(['table'], function (exports) { // 遍历字段 eachCols: table.eachCols, index: table.index, - set: function(options){ + set: function (options) { var that = this; that.config = $.extend({}, that.config, options); return that; @@ -540,7 +540,8 @@ layui.define(['table'], function (exports) { } } } else { - if (LAY_EXPAND == trData['LAY_EXPAND']) {} + if (LAY_EXPAND == trData['LAY_EXPAND']) { + } trData['LAY_EXPAND'] = LAY_EXPAND; // 折叠 if (sonSign && !isToggle) { // 非状态切换的情况下 @@ -605,9 +606,9 @@ layui.define(['table'], function (exports) { // 初始化的表格里面没有level信息,可以作为顶层节点的判断 tableViewElem.find('.layui-table-body tr:not([data-level])').attr('data-level', level); layui.each(table.cache[tableId], function (dataIndex, dataItem) { - tableViewElem.find('.layui-table-main tbody tr[data-level="0"]:eq('+dataIndex+')').attr('data-index', dataItem[LAY_DATA_INDEX]); - tableViewElem.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq('+dataIndex+')').attr('data-index', dataItem[LAY_DATA_INDEX]); - tableViewElem.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq('+dataIndex+')').attr('data-index', dataItem[LAY_DATA_INDEX]); + tableViewElem.find('.layui-table-main tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('data-index', dataItem[LAY_DATA_INDEX]); + tableViewElem.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('data-index', dataItem[LAY_DATA_INDEX]); + tableViewElem.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('data-index', dataItem[LAY_DATA_INDEX]); }) } @@ -696,20 +697,8 @@ layui.define(['table'], function (exports) { // 树表渲染 Class.prototype.render = function (type) { var that = this; - var options = that.config; - if (that.tableIns) { - // 已经在init的时候render一个表格实例了,理论上到这里都必然存在 - // 处理树节点状态 - that.tableIns = table[type === 'reloadData' ? 'reloadData' : 'reload'](that.tableIns.config.id, $.extend(true, {}, options)); - that.config = that.tableIns.config; - } else { - // console.log('真的会进去这个地方吗?2222'); - // var tableIns = table.render(options); - // options = that.config = tableIns.config; - // var id = options.id; - // thisTreeTable.that[id] = that; // 记录当前实例对象 - // that.tableIns = tableIns; // 记录关联的表格实例 - } + that.tableIns = table[type === 'reloadData' ? 'reloadData' : 'reload'](that.tableIns.config.id, $.extend(true, {}, that.config)); + that.config = that.tableIns.config; }; // 表格重载 @@ -740,14 +729,17 @@ layui.define(['table'], function (exports) { }; var updateStatus = function (data, statusObj, childrenKey) { + var dataUpdated = []; layui.each(data, function (i1, item1) { if (layui.type(statusObj) === 'function') { statusObj(item1); } else { $.extend(item1, statusObj); } - updateStatus(item1[childrenKey], statusObj, childrenKey); - }) + dataUpdated.push($.extend({}, item1)); + dataUpdated = dataUpdated.concat(updateStatus(item1[childrenKey], statusObj, childrenKey)); + }); + return dataUpdated; } Class.prototype.updateStatus = function (data, statusObj) { @@ -775,8 +767,7 @@ layui.define(['table'], function (exports) { data = options.data; } } - that.updateStatus(data, statusObj); - return options; + return that.updateStatus(data, statusObj); } treeTable.sort = function (id) { @@ -1004,6 +995,29 @@ layui.define(['table'], function (exports) { return newNodes; } + treeTable.checkStatus = function (id) { + var that = getThisTable(id); + + // 需要区分单双选 + var tableData = treeTable.getData(id, true); + var checkedData = tableData.filter(function (value, index, array) { + return value[table.config.checkName]; + }); + + var isAll = true; + layui.each(table.cache[id], function (i1, item1) { + if (!item1[table.config.checkName]) { + isAll = false; + return true; + } + }) + + return { + data: checkedData, + isAll: isAll + } + } + // 排序之后重新渲染成树表 treeTable.on('sort', function (obj) { var options = obj.config; @@ -1062,12 +1076,106 @@ layui.define(['table'], function (exports) { if (tableView.hasClass('layui-table-tree')) { updateObjParams(obj); if (obj.field === options.tree.data.key.name) { - obj.tr.find('td[data-field="'+obj.field+'"]').children('div.layui-table-cell').removeClass('layui-table-tree-item') + obj.tr.find('td[data-field="' + obj.field + '"]').children('div.layui-table-cell').removeClass('layui-table-tree-item') obj.update({}); // 通过update调用执行tr节点的更新 } } }); + // 单选 + treeTable.on('radio', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + var that = getThisTable(tableId); + + if (tableView.hasClass('layui-table-tree')) { + updateObjParams(obj); + var trIndex = obj.index; + var statusChecked = {}; + statusChecked[table.config.checkName] = false; + that.updateStatus(null, statusChecked); // 取消其他的选中状态 + table.cache[tableId][trIndex][table.config.checkName] = obj.checked; + } + }) + + Class.prototype.updateParentCheckStatus = function (dataP, checked) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + + var dataRet = []; + if (checked) { + // 为真需要判断子节点的情况 + var childrenKey = treeOptions.data.key.children; + layui.each(dataP[childrenKey], function (index, item) { + if (!item[table.config.checkName]) { // 只要有一个子节点为false + checked = false; + return true; // 跳出循环 + } + }); + } + dataP[table.config.checkName] = checked; + dataRet.push($.extend({}, dataP)); + if (dataP[LAY_PARENT_INDEX]) { + dataRet = dataRet.concat(that.updateParentCheckStatus(table.cache[tableId][dataP[LAY_PARENT_INDEX]], checked)); + } + return dataRet + } + + // 多选 + treeTable.on('checkbox', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + var that = getThisTable(tableId); + + if (tableView.hasClass('layui-table-tree')) { + updateObjParams(obj); + var checked = obj.checked; + var treeOptions = options.tree; + var isParentKey = treeOptions.data.key.isParent; + var childrenKey = treeOptions.data.key.children; + var trIndex = obj.index; + // 修改当前节点的信息 + var trData = table.cache[tableId][trIndex]; + // trData[table.config.checkName] = checked; + // tableView.find('tr[data-index="' + trIndex + '"] input[name="layTableCheckbox"]').prop('checked', checked); + // 如果是一个父节点,将子节点的状态同步为当前节点的状态,并且注意更深层次的 + if (obj.type === 'all' || trData[isParentKey]) { + var checkedStatus = {}; + checkedStatus[table.config.checkName] = checked; + var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatus); + form.render(tableView.find(trs.map(function (value) { + return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]'; + }).join(',')).prop('checked', checked)); + } + + // 更新父节点以及更上层节点的状态 + if (trData && trData[LAY_PARENT_INDEX]) { + // 找到父节点,然后判断父节点的子节点是否全部选中 + var trDataP = table.cache[tableId][trData[LAY_PARENT_INDEX]]; + var trsP = that.updateParentCheckStatus(trDataP, checked); + layui.each(trsP, function (indexP, itemP) { + form.render(tableView.find('tr[data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]').prop('checked', itemP[table.config.checkName])) + }) + } + + // 半选复选框的图标处理 todo + + // 全选图标的状态更新 + obj.isAll = true; + layui.each(table.cache[tableId], function (i1, item1) { + if (!item1[table.config.checkName]) { + obj.isAll = false; + return true; + } + }) + form.render(tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop('checked', obj.isAll)); + } + }) + /** * 获得数据 From 2c784041d8016a8e86891a05bda3cd0a9b5b05c8 Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Fri, 14 Apr 2023 15:04:59 +0800 Subject: [PATCH 10/15] =?UTF-8?q?form=E9=BB=98=E8=AE=A4=E7=9A=AE=E8=82=A4?= =?UTF-8?q?=E7=9A=84=E5=A4=8D=E9=80=89=E6=A1=86=E6=B7=BB=E5=8A=A0=E5=8D=8A?= =?UTF-8?q?=E9=80=89=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81=EF=BC=9B=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DtreeTable=E7=9A=84=E4=B8=80=E4=BA=9B=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/layui.css | 40 ++++----- src/modules/form.js | 9 ++- src/modules/treeTable.js | 170 ++++++++++++++++++++++++++------------- 3 files changed, 143 insertions(+), 76 deletions(-) diff --git a/src/css/layui.css b/src/css/layui.css index 8e828ddc..68de0302 100644 --- a/src/css/layui.css +++ b/src/css/layui.css @@ -55,7 +55,7 @@ a cite{font-style: normal; *cursor:pointer;} url('../font/iconfont.ttf?v=280') format('truetype'), url('../font/iconfont.svg?v=280#layui-icon') format('svg'); } - + .layui-icon{ font-family:"layui-icon" !important; font-size: 16px; @@ -367,7 +367,7 @@ a cite{font-style: normal; *cursor:pointer;} .layui-show-md-block{display: block!important;} .layui-show-md-inline{display: inline!important;} .layui-show-md-inline-block{display: inline-block!important;} - + .layui-col-md1, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9, .layui-col-md10, .layui-col-md11, .layui-col-md12{float: left;} .layui-col-md1{width: 8.33333333%;} .layui-col-md2{width: 16.66666667%;} @@ -402,7 +402,7 @@ a cite{font-style: normal; *cursor:pointer;} .layui-show-lg-block{display: block!important;} .layui-show-lg-inline{display: inline!important;} .layui-show-lg-inline-block{display: inline-block!important;} - + .layui-col-lg1, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12{float: left;} .layui-col-lg1{width: 8.33333333%;} .layui-col-lg2{width: 16.66666667%;} @@ -437,7 +437,7 @@ a cite{font-style: normal; *cursor:pointer;} .layui-show-xl-block{display: block!important;} .layui-show-xl-inline{display: inline!important;} .layui-show-xl-inline-block{display: inline-block!important;} - + .layui-col-xl1, .layui-col-xl2, .layui-col-xl3, .layui-col-xl4, .layui-col-xl5, .layui-col-xl6, .layui-col-xl7, .layui-col-xl8, .layui-col-xl9, .layui-col-xl10, .layui-col-xl11, .layui-col-xl12{float: left;} .layui-col-xl1{width: 8.33333333%;} .layui-col-xl2{width: 16.66666667%;} @@ -532,7 +532,7 @@ a cite{font-style: normal; *cursor:pointer;} /* 面板 - + */ @@ -566,8 +566,8 @@ a cite{font-style: normal; *cursor:pointer;} .layui-scollbar-hide{overflow: hidden !important;} -/* - * 默认主题 +/* + * 默认主题 */ @@ -582,11 +582,11 @@ a cite{font-style: normal; *cursor:pointer;} /* 边框 */ .layui-border, -.layui-quote-nm, +.layui-quote-nm, .layui-elem-field, -.layui-collapse, +.layui-collapse, .layui-panel, -.layui-colla-item, +.layui-colla-item, .layui-colla-content, .layui-badge-rim, .layui-tab-title, @@ -596,7 +596,7 @@ a cite{font-style: normal; *cursor:pointer;} .layui-input, .layui-textarea, .layui-select, .layui-input-split, -.layui-form-pane .layui-form-label, +.layui-form-pane .layui-form-label, .layui-form-pane .layui-form-item[pane]{border-color: #eee;} .layui-border{border-width: 1px; border-style: solid; color: #5F5F5F!important;} @@ -663,8 +663,8 @@ a cite{font-style: normal; *cursor:pointer;} /* - - 按钮 + + 按钮 */ @@ -716,7 +716,7 @@ a cite{font-style: normal; *cursor:pointer;} .layui-input:focus, .layui-textarea:focus{border-color: #d2d2d2 !important;} .layui-textarea{position: relative; min-height: 100px; height: auto; line-height: 20px; padding: 6px 10px; resize: vertical;} .layui-select{padding: 0 10px;} -.layui-form select, +.layui-form select, .layui-form input[type=checkbox], .layui-form input[type=radio]{display: none;} .layui-form *[lay-ignore]{display: initial;} @@ -831,6 +831,8 @@ a cite{font-style: normal; *cursor:pointer;} .layui-form-checked.layui-checkbox-disabled[lay-skin="primary"] i{background: #eee!important; border-color: #eee!important;} .layui-checkbox-disabled[lay-skin="primary"]:hover i{border-color: #d2d2d2;} .layui-form-item .layui-form-checkbox[lay-skin="primary"]{margin-top: 10px;} +.layui-form-checkbox[lay-skin="primary"] > i.layui-icon-subtraction, +.layui-form-checkbox[lay-skin="primary"]:hover i.layui-icon-subtraction {color: darkgray;} /* 复选框-开关风格 */.layui-form-switch{position: relative; display: inline-block; vertical-align: middle; height: 22px; line-height: 22px; min-width: 35px; padding: 0 5px; margin-top: 8px; border: 1px solid #d2d2d2; border-radius: 20px; cursor: pointer; background-color: #fff; -webkit-transition: .1s linear; transition: .1s linear;} .layui-form-switch i{position: absolute; left: 5px; top: 3px; width: 16px; height: 16px; border-radius: 20px; background-color: #d2d2d2; -webkit-transition: .1s linear; transition: .1s linear;} @@ -865,7 +867,7 @@ a cite{font-style: normal; *cursor:pointer;} .layui-form-pane .layui-form-text .layui-input-block{margin: 0; left: 0; top: -1px;} .layui-form-pane .layui-form-text .layui-textarea{min-height: 100px; border-radius: 0 0 2px 2px;} .layui-form-pane .layui-form-checkbox{margin: 4px 0 4px 10px;} -.layui-form-pane .layui-form-switch, +.layui-form-pane .layui-form-switch, .layui-form-pane .layui-form-radio{margin-top: 6px; margin-left: 10px; } .layui-form-pane .layui-form-item[pane]{position: relative; border-width: 1px; border-style: solid;} .layui-form-pane .layui-form-item[pane] .layui-form-label{position: absolute; left: 0; top: 0; height: 100%; border-width: 0px; border-right-width: 1px;} @@ -891,7 +893,7 @@ a cite{font-style: normal; *cursor:pointer;} .layui-laypage>*:last-child{margin-right: 0!important;} .layui-laypage a, .layui-laypage span, -.layui-laypage input, +.layui-laypage input, .layui-laypage button, .layui-laypage select{border: 1px solid #eee;} .layui-laypage a, @@ -1239,7 +1241,7 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh .layui-nav-tree .layui-nav-child a:hover, .layui-nav-tree .layui-nav-child{background: none; color: #fff;} -.layui-nav-itemed>.layui-nav-child{display: block; background-color: rgba(0,0,0,.3) !important;} +.layui-nav-itemed>.layui-nav-child{display: block; background-color: rgba(0,0,0,.3) !important;} .layui-nav-itemed>.layui-nav-child>.layui-this>.layui-nav-child{display: block;} /* 侧边 */.layui-nav-side{position: fixed; top: 0; bottom: 0; left: 0; overflow-x: hidden; z-index: 999;} @@ -1480,7 +1482,7 @@ body .layui-util-face .layui-layer-content{padding:0; background-color:#fff; co .layui-slider-wrap{width: 36px; height: 36px; position: absolute; top: -16px; -webkit-transform: translateX(-50%); transform: translateX(-50%); z-index: 10; text-align: center;} .layui-slider-wrap-btn{width: 12px; height: 12px; border-radius: 50%; background: #FFF; display: inline-block; vertical-align: middle; cursor: pointer; transition: 0.3s;} .layui-slider-wrap:after{content: ""; height: 100%; display: inline-block; vertical-align: middle;} -.layui-slider-wrap-btn:hover, +.layui-slider-wrap-btn:hover, .layui-slider-wrap-btn.layui-slider-hover{transform: scale(1.2);} .layui-slider-wrap-btn.layui-disabled:hover{transform: scale(1) !important;} .layui-slider-tips{position: absolute; top: -42px; z-index: 77777777; white-space:nowrap; display: none; -webkit-transform: translateX(-50%); transform: translateX(-50%); color: #FFF; background: #000; border-radius: 3px; height: 25px; line-height: 25px; padding: 0 10px;} @@ -1645,7 +1647,7 @@ body .layui-util-face .layui-layer-content{padding:0; background-color:#fff; co .layui-anim-fadein{-webkit-animation-name: layui-fadein; animation-name: layui-fadein;} /* 渐隐 */ -@-webkit-keyframes layui-fadeout { +@-webkit-keyframes layui-fadeout { 0% {opacity: 1;} 100% {opacity: 0;} } diff --git a/src/modules/form.js b/src/modules/form.js index db472973..778dde2e 100644 --- a/src/modules/form.js +++ b/src/modules/form.js @@ -642,7 +642,12 @@ layui.define(['lay', 'layer', 'util'], function(exports){ var title = (check.attr('title')||'').split('|'); if(check[0].disabled) return; - + if (check[0].indeterminate) { + check[0].indeterminate = false; + reElem.find('.layui-icon-subtraction').removeClass('layui-icon-subtraction').addClass('layui-icon-ok') + } + + check[0].checked ? ( check[0].checked = false ,reElem.removeClass(RE_CLASS[1]).find('em').text(title[1]) @@ -686,7 +691,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){ // 复选框 "checkbox": [ (title[0] ? (''+ util.escape(title[0]) +'') : '') - ,'' + ,'' ].join(''), // 开关 diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index ff5c56d9..2c179790 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -85,6 +85,7 @@ layui.define(['table'], function (exports) { var LAY_DATA_INDEX = 'LAY_DATA_INDEX'; var LAY_DATA_INDEX_HISTORY = 'LAY_DATA_INDEX_HISTORY'; var LAY_PARENT_INDEX = 'LAY_PARENT_INDEX'; + var LAY_CHECKBOX_HALF = 'LAY_CHECKBOX_HALF'; // 构造器 var Class = function (options) { @@ -149,6 +150,17 @@ layui.define(['table'], function (exports) { that.initData(options.data); } + var updateCache = function (data) { + var tableCache = table.cache[id]; + layui.each(data || tableCache, function (index, item) { + var itemDataIndex = item[LAY_DATA_INDEX]; + if (itemDataIndex.indexOf('-') !== -1) { + tableCache[itemDataIndex] = item + } + item[childrenKey] && updateCache(item[childrenKey]); + }) + } + options.done = function () { var args = arguments; var doneThat = this; @@ -156,7 +168,10 @@ layui.define(['table'], function (exports) { var tableView = this.elem.next(); that.updateStatus(null, { LAY_HAS_EXPANDED: false // 去除已经打开过的状态 - }) + }); + // 更新cache中的内容 将子节点也存到cache中 + updateCache(); + that.renderTreeTable(tableView); if (layui.type(done) === 'function') { @@ -349,7 +364,6 @@ layui.define(['table'], function (exports) { item1[LAY_DATA_INDEX_HISTORY] = item1[LAY_DATA_INDEX]; item1[LAY_PARENT_INDEX] = parentIndex = parentIndex || ''; var dataIndex = item1[LAY_DATA_INDEX] = (parentIndex ? parentIndex + '-' : '') + i1; - dataIndex.indexOf('-') !== -1 && (table.cache[tableId][dataIndex] = item1); that.initData(item1[childrenKey] || [], dataIndex); }); @@ -365,7 +379,7 @@ layui.define(['table'], function (exports) { var options = table.getOptions(tableId); var treeOptions = options.tree || {}; var isParentKey = treeOptions.data.key.isParent; - var trIndex = trElem.attr('data-index'); // 可能出现多层 + var trIndex = trElem.attr('lay-data-index'); // 可能出现多层 var treeTableThat = getThisTable(tableId); var tableData = treeTableThat.getTableData(); @@ -391,8 +405,8 @@ layui.define(['table'], function (exports) { var LAY_HAS_EXPANDED = trData['LAY_HAS_EXPANDED']; // 展开过,包括异步加载 - // 找到表格中的同类节点(需要找到data-index一致的所有行) - var trsElem = tableViewElem.find('tr[data-index="' + trIndex + '"]'); + // 找到表格中的同类节点(需要找到lay-data-index一致的所有行) + var trsElem = tableViewElem.find('tr[lay-data-index="' + trIndex + '"]'); // 处理折叠按钮图标 var flexIconElem = trsElem.find('.layui-table-tree-flexIcon'); flexIconElem.html(LAY_EXPAND ? treeOptions.view.flexIconOpen : treeOptions.view.flexIconClose) @@ -413,15 +427,15 @@ layui.define(['table'], function (exports) { trData['LAY_EXPAND'] = LAY_EXPAND; tableViewElem.find(childNodes.map(function (value, index, array) { - return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(',')).removeClass('layui-hide'); layui.each(childNodes, function (i1, item1) { if (sonSign && !isToggle) { // 非状态切换的情况下 // 级联展开子节点 - expandNode({trElem: tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); + expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); } else if (item1.LAY_EXPAND) { // 级联展开 - expandNode({trElem: tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, true); + expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, true); } }) } else { @@ -511,20 +525,26 @@ layui.define(['table'], function (exports) { trs_fixed_r: $(str2.trs_fixed_r.join('')) } layui.each(childNodes, function (childIndex, childItem) { - str2Obj.trs.eq(childIndex).attr({'data-index': childItem[LAY_DATA_INDEX], 'data-level': dataLevelNew}) + str2Obj.trs.eq(childIndex).attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew + }) str2Obj.trs_fixed.eq(childIndex).attr({ 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], 'data-level': dataLevelNew }) str2Obj.trs_fixed_r.eq(childIndex).attr({ 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], 'data-level': dataLevelNew }) }) - tableViewElem.find(ELEM_MAIN).find('tbody tr[data-index="' + trIndex + '"]').after(str2Obj.trs); - tableViewElem.find(ELEM_FIXL).find('tbody tr[data-index="' + trIndex + '"]').after(str2Obj.trs_fixed); - tableViewElem.find(ELEM_FIXR).find('tbody tr[data-index="' + trIndex + '"]').after(str2Obj.trs_fixed_r); + tableViewElem.find(ELEM_MAIN).find('tbody tr[lay-data-index="' + trIndex + '"]').after(str2Obj.trs); + tableViewElem.find(ELEM_FIXL).find('tbody tr[lay-data-index="' + trIndex + '"]').after(str2Obj.trs_fixed); + tableViewElem.find(ELEM_FIXR).find('tbody tr[lay-data-index="' + trIndex + '"]').after(str2Obj.trs_fixed_r); // 初始化新增的节点中的内容 layui.each(str2Obj, function (key, item) { @@ -534,7 +554,7 @@ layui.define(['table'], function (exports) { if (sonSign && !isToggle) { // 非状态切换的情况下 // 级联展开/关闭子节点 layui.each(childNodes, function (i1, item1) { - expandNode({trElem: tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); + expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); }) } } @@ -546,15 +566,15 @@ layui.define(['table'], function (exports) { // 折叠 if (sonSign && !isToggle) { // 非状态切换的情况下 layui.each(childNodes, function (i1, item1) { - expandNode({trElem: tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); + expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); }); tableViewElem.find(childNodes.map(function (value, index, array) { // 只隐藏直接子节点,其他由递归的处理 - return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(',')).addClass('layui-hide'); } else { var childNodesFlat = treeTableThat.treeToFlat(childNodes, trData[treeOptions.data.simpleData.idKey], trIndex); tableViewElem.find(childNodesFlat.map(function (value, index, array) { - return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(',')).addClass('layui-hide'); } @@ -573,7 +593,7 @@ layui.define(['table'], function (exports) { var that = getThisTable(id); var options = that.getOptions(); var tableViewElem = options.elem.next(); - return expandNode({trElem: tableViewElem.find('tr[data-index="' + index + '"]').first()}, expandFlag, sonSign, null, callbackFlag) + return expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + index + '"]').first()}, expandFlag, sonSign, null, callbackFlag) } // 目前还有性能问题特别是在data模式需要优化暂时不能使用 todo @@ -606,9 +626,9 @@ layui.define(['table'], function (exports) { // 初始化的表格里面没有level信息,可以作为顶层节点的判断 tableViewElem.find('.layui-table-body tr:not([data-level])').attr('data-level', level); layui.each(table.cache[tableId], function (dataIndex, dataItem) { - tableViewElem.find('.layui-table-main tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('data-index', dataItem[LAY_DATA_INDEX]); - tableViewElem.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('data-index', dataItem[LAY_DATA_INDEX]); - tableViewElem.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('data-index', dataItem[LAY_DATA_INDEX]); + tableViewElem.find('.layui-table-main tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('lay-data-index', dataItem[LAY_DATA_INDEX]); + tableViewElem.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('lay-data-index', dataItem[LAY_DATA_INDEX]); + tableViewElem.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('lay-data-index', dataItem[LAY_DATA_INDEX]); }) } @@ -624,7 +644,7 @@ layui.define(['table'], function (exports) { return; } itemCell.addClass('layui-table-tree-item'); - var trIndex = trElem.attr('data-index'); + var trIndex = trElem.attr('lay-data-index'); if (!trIndex) { // 排除在统计行中的节点 return; } @@ -662,7 +682,7 @@ layui.define(['table'], function (exports) { // 当前层的数据看看是否需要展开 sonSign !== false && layui.each(dataExpand, function (index, item) { - var trDefaultExpand = tableViewElem.find('tr[data-index="' + index + '"]'); + var trDefaultExpand = tableViewElem.find('tr[lay-data-index="' + index + '"]'); trDefaultExpand.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconOpen); expandNode({trElem: trDefaultExpand.first()}, true); }); @@ -689,7 +709,7 @@ layui.define(['table'], function (exports) { } var itemData = that.getNodeDataByIndex(item1.LAY_DATA_INDEX); itemData['LAY_NUM'] = ++num; - tableViewElem.find('tr[data-index="' + item1.LAY_DATA_INDEX + '"] .laytable-cell-numbers').html(itemData['LAY_NUM']); + tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"] .laytable-cell-numbers').html(itemData['LAY_NUM']); }) return treeTable; } @@ -826,7 +846,9 @@ layui.define(['table'], function (exports) { var options = that.getOptions(); var treeOptions = options.tree; var tableView = options.elem.next(); - var trLevel = tableView.find('tr[data-index="' + index + '"]').attr('data-level') + var trElem = tableView.find('tr[lay-data-index="' + index + '"]'); + var trIndex = trElem.attr('data-index'); + var trLevel = trElem.attr('data-level') if (!newNode) { return; @@ -835,11 +857,15 @@ layui.define(['table'], function (exports) { var newNodeTemp = that.getNodeDataByIndex(index, false, newNode); // 获取新的tr替换 var trNew = table.getTrHtml(id, [newNodeTemp]); + debugger; // 重新渲染tr layui.each(['main', 'fixed-l', 'fixed-r'], function (i, item) { - tableView.find('.layui-table-' + item + ' tbody tr[data-index="' + index + '"]').replaceWith($(trNew[['trs', 'trs_fixed', 'trs_fixed_r'][i]].join('')).attr('data-index', index)); + tableView.find('.layui-table-' + item + ' tbody tr[lay-data-index="' + index + '"]').replaceWith($(trNew[['trs', 'trs_fixed', 'trs_fixed_r'][i]].join('')).attr({ + 'data-index': trIndex, + 'lay-data-index': index, + })); }); - that.renderTreeTable(tableView.find('tr[data-index="' + index + '"]'), trLevel); + that.renderTreeTable(tableView.find('tr[lay-data-index="' + index + '"]'), trLevel); } // 删除数据 @@ -857,20 +883,27 @@ layui.define(['table'], function (exports) { delNode = that.getNodeDataByIndex(indexValue, false, 'delete'); var delNodesFlat = that.treeToFlat([delNode], delNode[treeOptions.data.simpleData.pIdKey], delNode[LAY_PARENT_INDEX]); layui.each(delNodesFlat, function (i2, item2) { - indexArr.push('tr[data-index="' + item2[LAY_DATA_INDEX] + '"]'); + indexArr.push('tr[lay-data-index="' + item2[LAY_DATA_INDEX] + '"]'); }) }); tableView.find(indexArr.join(',')).remove(); // 删除行 // 重新整理数据 var tableData = that.initData(); - // index发生变化需要更新页面tr中对应的data-index 新增和删除都要注意数据结构变动之后的index问题 + // index发生变化需要更新页面tr中对应的lay-data-index 新增和删除都要注意数据结构变动之后的index问题 layui.each(that.treeToFlat(tableData), function (i3, item3) { if (item3[LAY_DATA_INDEX_HISTORY] && item3[LAY_DATA_INDEX_HISTORY] !== item3[LAY_DATA_INDEX]) { - tableView.find('tr[data-index="' + item3[LAY_DATA_INDEX_HISTORY] + '"]').attr('data-index', item3[LAY_DATA_INDEX]); - item3[LAY_DATA_INDEX_HISTORY] = item3[LAY_DATA_INDEX]; + tableView.find('tr[lay-data-index="' + item3[LAY_DATA_INDEX_HISTORY] + '"]').attr({ + 'data-index': item3[LAY_DATA_INDEX], + 'lay-data-index': item3[LAY_DATA_INDEX], + }); + // item3[LAY_DATA_INDEX_HISTORY] = item3[LAY_DATA_INDEX] } }); + // 重新更新顶层节点的data-index; + layui.each(table.cache[id], function (i4, item4) { + tableView.find('tr[data-level="0"][lay-data-index="' + item4[LAY_DATA_INDEX] + '"]').attr('data-index', i4); + }) treeTable.formatNumber(id); } @@ -920,13 +953,19 @@ layui.define(['table'], function (exports) { } layui.each(newNodes, function (newNodeIndex, newNodeItem) { - newNodesHtmlObj.trs.eq(newNodeIndex).attr({'data-index': newNodeItem[LAY_DATA_INDEX], 'data-level': '0'}) + newNodesHtmlObj.trs.eq(newNodeIndex).attr({ + 'data-index': newNodeItem[LAY_DATA_INDEX], + 'lay-data-index': newNodeItem[LAY_DATA_INDEX], + 'data-level': '0' + }) newNodesHtmlObj.trs_fixed.eq(newNodeIndex).attr({ 'data-index': newNodeItem[LAY_DATA_INDEX], + 'lay-data-index': newNodeItem[LAY_DATA_INDEX], 'data-level': '0' }) newNodesHtmlObj.trs_fixed_r.eq(newNodeIndex).attr({ 'data-index': newNodeItem[LAY_DATA_INDEX], + 'lay-data-index': newNodeItem[LAY_DATA_INDEX], 'data-level': '0' }) }) @@ -954,14 +993,13 @@ layui.define(['table'], function (exports) { } - // 更新编号 - // layui.each(tableData, function (i1, item1) { - // tableViewElemMAIN.find('tr[data-level="0"]').eq(i1).attr('data-index', item1[LAY_DATA_INDEX]); - // tableViewElemFIXL.find('tr[data-level="0"]').eq(i1).attr('data-index', item1[LAY_DATA_INDEX]); - // tableViewElemFIXR.find('tr[data-level="0"]').eq(i1).attr('data-index', item1[LAY_DATA_INDEX]); - // }) + // 重新更新顶层节点的data-index; + layui.each(table.cache[id], function (i4, item4) { + tableViewElem.find('tr[data-level="0"][lay-data-index="' + item4[LAY_DATA_INDEX] + '"]').attr('data-index', i4); + }) + that.renderTreeTable(tableViewElem.find(newNodes.map(function (value, index, array) { - return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(','))); } else { var isParentKey = treeOptions.data.key.isParent; @@ -983,14 +1021,14 @@ layui.define(['table'], function (exports) { }); var childrenNodesFlat = that.treeToFlat(childrenNodes); tableViewElem.find(childrenNodesFlat.map(function (value) { - return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"]' + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(',')).remove(); tableData = that.initData(); // 去掉父节点的已经展开过的状态,重新执行一次展开的方法 parentNode['LAY_HAS_EXPANDED'] = false; parentNode['LAY_ASYNC_STATUS'] = 'local'; // 转为本地数据,应该规定异步加载子节点的时候addNodes的规则 - expandNode({trElem: tableViewElem.find('tr[data-index="' + parentIndex + '"]')}, true) + expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + parentIndex + '"]')}, true) } return newNodes; } @@ -1099,24 +1137,36 @@ layui.define(['table'], function (exports) { } }) + // 更新父节点的选中状态 Class.prototype.updateParentCheckStatus = function (dataP, checked) { var that = this; var options = that.getOptions(); var treeOptions = options.tree; var tableId = options.id; + var checkName = table.config.checkName; + var childrenKey = treeOptions.data.key.children; var dataRet = []; + dataP[LAY_CHECKBOX_HALF] = false; // 先设置为非半选,是否为半选又下面逻辑判断 if (checked) { // 为真需要判断子节点的情况 - var childrenKey = treeOptions.data.key.children; layui.each(dataP[childrenKey], function (index, item) { - if (!item[table.config.checkName]) { // 只要有一个子节点为false + if (!item[checkName]) { // 只要有一个子节点为false checked = false; + dataP[LAY_CHECKBOX_HALF] = true; return true; // 跳出循环 } }); + } else { + // 判断是否为半选 + layui.each(dataP[childrenKey], function (index, item) { + if (item[checkName] || item[LAY_CHECKBOX_HALF]) { // 只要有一个子节点为选中或者半选状态 + dataP[LAY_CHECKBOX_HALF] = true; + return true; + } + }); } - dataP[table.config.checkName] = checked; + dataP[checkName] = checked; dataRet.push($.extend({}, dataP)); if (dataP[LAY_PARENT_INDEX]) { dataRet = dataRet.concat(that.updateParentCheckStatus(table.cache[tableId][dataP[LAY_PARENT_INDEX]], checked)); @@ -1138,41 +1188,51 @@ layui.define(['table'], function (exports) { var isParentKey = treeOptions.data.key.isParent; var childrenKey = treeOptions.data.key.children; var trIndex = obj.index; + var checkName = table.config.checkName; // 修改当前节点的信息 - var trData = table.cache[tableId][trIndex]; - // trData[table.config.checkName] = checked; - // tableView.find('tr[data-index="' + trIndex + '"] input[name="layTableCheckbox"]').prop('checked', checked); + var trData = that.getNodeDataByIndex(trIndex); + // trData[checkName] = checked; // 如果是一个父节点,将子节点的状态同步为当前节点的状态,并且注意更深层次的 if (obj.type === 'all' || trData[isParentKey]) { var checkedStatus = {}; - checkedStatus[table.config.checkName] = checked; + checkedStatus[checkName] = checked; + checkedStatus[LAY_CHECKBOX_HALF] = false; var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatus); form.render(tableView.find(trs.map(function (value) { - return 'tr[data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]'; - }).join(',')).prop('checked', checked)); + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]'; + }).join(',')).prop({checked: checked, indeterminate: false})); } // 更新父节点以及更上层节点的状态 if (trData && trData[LAY_PARENT_INDEX]) { // 找到父节点,然后判断父节点的子节点是否全部选中 - var trDataP = table.cache[tableId][trData[LAY_PARENT_INDEX]]; + var trDataP = that.getNodeDataByIndex(trData[LAY_PARENT_INDEX]); var trsP = that.updateParentCheckStatus(trDataP, checked); layui.each(trsP, function (indexP, itemP) { - form.render(tableView.find('tr[data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]').prop('checked', itemP[table.config.checkName])) + form.render(tableView.find('tr[lay-data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]').prop({ + checked: itemP[checkName], + indeterminate: itemP[LAY_CHECKBOX_HALF] + })) }) } - // 半选复选框的图标处理 todo - // 全选图标的状态更新 obj.isAll = true; + var isIndeterminate = false; layui.each(table.cache[tableId], function (i1, item1) { - if (!item1[table.config.checkName]) { + if (item1[checkName] || item1[LAY_CHECKBOX_HALF]) { + isIndeterminate = true; + } + if (!item1[checkName]) { obj.isAll = false; return true; } }) - form.render(tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop('checked', obj.isAll)); + isIndeterminate = isIndeterminate && !obj.isAll; + form.render(tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({ + 'checked': obj.isAll, + indeterminate: isIndeterminate + })); } }) From d412b90320c27f954507f2eedadbafbca79040ed Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Fri, 14 Apr 2023 18:27:18 +0800 Subject: [PATCH 11/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E4=B9=8B=E5=90=8E=E7=9B=B8=E5=85=B3=E7=9A=84?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=A4=8D=E9=80=89=E6=A1=86=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/layui.css | 7 ++- src/modules/treeTable.js | 129 ++++++++++++++++++++++++++++----------- 2 files changed, 97 insertions(+), 39 deletions(-) diff --git a/src/css/layui.css b/src/css/layui.css index 68de0302..87c82bb1 100644 --- a/src/css/layui.css +++ b/src/css/layui.css @@ -1108,10 +1108,13 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh .layui-table-tips-c:before{position: relative; right: -2px;} /** 树表 **/ -.layui-table-tree-nodeIcon {padding-right: 2px;width: 20px;} +.layui-table-tree .layui-table-cell {display: inline-flex; align-items: center;} +.layui-table-tree-nodeIcon {width: 20px;} .layui-table-tree-nodeIcon > * {width: 100%;} +.layui-table-tree-flexIcon,.layui-table-tree-nodeIcon {margin-right: 2px;} +.layui-table-tree-flexIcon {cursor: pointer;} -/** 文件上传 **/ + /** 文件上传 **/ .layui-upload-file{display: none!important; opacity: .01; filter: Alpha(opacity=1);} .layui-upload-list{margin: 11px 0;} .layui-upload-choose{max-width: 200px; padding: 0 10px; color: #999; font-size: 14px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;} diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index 2c179790..0e474628 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -171,6 +171,15 @@ layui.define(['table'], function (exports) { }); // 更新cache中的内容 将子节点也存到cache中 updateCache(); + // 更新全选框的状态 + var layTableAllChooseElem = tableView.find('[name="layTableCheckbox"][lay-filter="layTableAllChoose"]'); + if (layTableAllChooseElem.length) { + var checkStatus = treeTable.checkStatus(id); + layTableAllChooseElem.prop({ + checked: checkStatus.isAll && checkStatus.data.length, + indeterminate: !checkStatus.isAll && checkStatus.data.length + }) + } that.renderTreeTable(tableView); @@ -661,7 +670,7 @@ layui.define(['table'], function (exports) { .html(['
', treeOptions.view.flexIconClose, // 折叠图标 '
', @@ -814,6 +823,7 @@ layui.define(['table'], function (exports) { var tableThat = getThisTable(tableId); var trData = obj.data = treeTable.getNodeDataByIndex(tableId, obj.index); // 克隆的 var trIndex = trData[LAY_DATA_INDEX]; + obj.dataIndex = trIndex; // 处理update方法 var updateFn = obj.update; @@ -827,17 +837,9 @@ layui.define(['table'], function (exports) { } // 处理del方法 - var delFn = obj.del; obj.del = function () { - var updateThat = this; - var args = arguments; - // 原始的方法是讲对应下标的元素换成空数组,并删除相关节点,已经由 - // var ret = delFn.apply(updateThat, args); - // delete table.cache[tableId][trIndex]; treeTable.removeNode(tableId, trIndex); - // return ret; } - } // 更新数据 @@ -857,7 +859,6 @@ layui.define(['table'], function (exports) { var newNodeTemp = that.getNodeDataByIndex(index, false, newNode); // 获取新的tr替换 var trNew = table.getTrHtml(id, [newNodeTemp]); - debugger; // 重新渲染tr layui.each(['main', 'fixed-l', 'fixed-r'], function (i, item) { tableView.find('.layui-table-' + item + ' tbody tr[lay-data-index="' + index + '"]').replaceWith($(trNew[['trs', 'trs_fixed', 'trs_fixed_r'][i]].join('')).attr({ @@ -881,6 +882,8 @@ layui.define(['table'], function (exports) { var indexArr = []; layui.each(index, function (index, indexValue) { delNode = that.getNodeDataByIndex(indexValue, false, 'delete'); + var nodeP = that.getNodeDataByIndex(delNode[LAY_PARENT_INDEX]); + that.updateCheckStatus(nodeP, true);// 删除节点接近取消选择 todo var delNodesFlat = that.treeToFlat([delNode], delNode[treeOptions.data.simpleData.pIdKey], delNode[LAY_PARENT_INDEX]); layui.each(delNodesFlat, function (i2, item2) { indexArr.push('tr[lay-data-index="' + item2[LAY_DATA_INDEX] + '"]'); @@ -1137,6 +1140,47 @@ layui.define(['table'], function (exports) { } }) + // 更新表格的复选框状态 + Class.prototype.updateCheckStatus = function (dataP, checked) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + var tableView = options.elem.next(); + + var checkName = table.config.checkName; + + // 如有必要更新父节点们的状态 + if (dataP) { + var trsP = that.updateParentCheckStatus(dataP, checked); + layui.each(trsP, function (indexP, itemP) { + form.render(tableView.find('tr[lay-data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)').prop({ + checked: itemP[checkName], + indeterminate: itemP[LAY_CHECKBOX_HALF] + })) + }) + } + + // 更新全选的状态 + var isAll = true; + var isIndeterminate = false; + layui.each(table.cache[tableId], function (i1, item1) { + if (item1[checkName] || item1[LAY_CHECKBOX_HALF]) { + isIndeterminate = true; + } + if (!item1[checkName]) { + isAll = false; + } + }) + isIndeterminate = isIndeterminate && !isAll; + form.render(tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({ + 'checked': isAll, + indeterminate: isIndeterminate + })); + + return isAll + } + // 更新父节点的选中状态 Class.prototype.updateParentCheckStatus = function (dataP, checked) { var that = this; @@ -1197,42 +1241,53 @@ layui.define(['table'], function (exports) { var checkedStatus = {}; checkedStatus[checkName] = checked; checkedStatus[LAY_CHECKBOX_HALF] = false; - var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatus); + + // 处理不可操作的信息 + var checkedStatusFn = function (d) { + if (!d[table.config.disabledName]) { // 节点不可操作的不处理 + d[checkName] = checked; + d[LAY_CHECKBOX_HALF] = false; + } + } + + // var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatus); + var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatusFn); form.render(tableView.find(trs.map(function (value) { - return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]'; + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)'; }).join(',')).prop({checked: checked, indeterminate: false})); } - + var trDataP; // 更新父节点以及更上层节点的状态 if (trData && trData[LAY_PARENT_INDEX]) { // 找到父节点,然后判断父节点的子节点是否全部选中 - var trDataP = that.getNodeDataByIndex(trData[LAY_PARENT_INDEX]); - var trsP = that.updateParentCheckStatus(trDataP, checked); - layui.each(trsP, function (indexP, itemP) { - form.render(tableView.find('tr[lay-data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]').prop({ - checked: itemP[checkName], - indeterminate: itemP[LAY_CHECKBOX_HALF] - })) - }) + trDataP = that.getNodeDataByIndex(trData[LAY_PARENT_INDEX]); + // var trsP = that.updateParentCheckStatus(trDataP, checked); + // layui.each(trsP, function (indexP, itemP) { + // form.render(tableView.find('tr[lay-data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)').prop({ + // checked: itemP[checkName], + // indeterminate: itemP[LAY_CHECKBOX_HALF] + // })) + // }) } + obj.isAll = that.updateCheckStatus(trDataP, checked); + // 全选图标的状态更新 - obj.isAll = true; - var isIndeterminate = false; - layui.each(table.cache[tableId], function (i1, item1) { - if (item1[checkName] || item1[LAY_CHECKBOX_HALF]) { - isIndeterminate = true; - } - if (!item1[checkName]) { - obj.isAll = false; - return true; - } - }) - isIndeterminate = isIndeterminate && !obj.isAll; - form.render(tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({ - 'checked': obj.isAll, - indeterminate: isIndeterminate - })); + // obj.isAll = true; + // var isIndeterminate = false; + // layui.each(table.cache[tableId], function (i1, item1) { + // if (item1[checkName] || item1[LAY_CHECKBOX_HALF]) { + // isIndeterminate = true; + // } + // if (!item1[checkName]) { + // obj.isAll = false; + // } + // }) + // isIndeterminate = isIndeterminate && !obj.isAll; + // form.render(tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({ + // 'checked': obj.isAll, + // indeterminate: isIndeterminate + // })); } }) From fa9dc386af813712cce4cba74ca5c2f339bb7f42 Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <470459819@qq.com> Date: Mon, 17 Apr 2023 03:01:27 +0800 Subject: [PATCH 12/15] =?UTF-8?q?treeTable=E4=BF=AE=E5=A4=8D=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E9=97=AE=E9=A2=98=EF=BC=8C=E8=B0=83=E6=95=B4removeNod?= =?UTF-8?q?e=E6=96=B9=E6=B3=95=E7=9A=84=E5=8F=82=E6=95=B0=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=80=E4=BA=9B=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/layui.css | 1 - src/modules/treeTable.js | 133 +++++++++++++++++++++++++-------------- 2 files changed, 85 insertions(+), 49 deletions(-) diff --git a/src/css/layui.css b/src/css/layui.css index 87c82bb1..0a22ed0f 100644 --- a/src/css/layui.css +++ b/src/css/layui.css @@ -1108,7 +1108,6 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh .layui-table-tips-c:before{position: relative; right: -2px;} /** 树表 **/ -.layui-table-tree .layui-table-cell {display: inline-flex; align-items: center;} .layui-table-tree-nodeIcon {width: 20px;} .layui-table-tree-nodeIcon > * {width: 100%;} .layui-table-tree-flexIcon,.layui-table-tree-nodeIcon {margin-right: 2px;} diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index 0e474628..187b95e2 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -24,6 +24,7 @@ layui.define(['table'], function (exports) { that.config = $.extend({}, that.config, options); return that; }, + resize: table.resize }; // 操作当前实例 @@ -86,6 +87,8 @@ layui.define(['table'], function (exports) { var LAY_DATA_INDEX_HISTORY = 'LAY_DATA_INDEX_HISTORY'; var LAY_PARENT_INDEX = 'LAY_PARENT_INDEX'; var LAY_CHECKBOX_HALF = 'LAY_CHECKBOX_HALF'; + var LAY_EXPAND = 'LAY_EXPAND'; + var LAY_HAS_EXPANDED = 'LAY_HAS_EXPANDED'; // 构造器 var Class = function (options) { @@ -247,7 +250,7 @@ layui.define(['table'], function (exports) { } }; - function flatToTree(flatArr, idKey, pIdKey, childrenKey) { + function flatToTree(flatArr, idKey, pIdKey, childrenKey, rootPId) { idKey = idKey || 'id'; pIdKey = pIdKey || 'parentId'; childrenKey = childrenKey || 'children'; @@ -264,9 +267,9 @@ layui.define(['table'], function (exports) { nodes[item[pIdKey]][childrenKey].push(item); } }) - // 返回顶层节点,即所有节点中 parentId 为 null 的节点 + // 返回顶层节点 return Object.values(nodes).filter(function (item) { - return !item[pIdKey]; + return rootPId ? item[pIdKey] === rootPId : !item[pIdKey]; }) } @@ -274,11 +277,12 @@ layui.define(['table'], function (exports) { var that = this; var options = that.getOptions(); var treeOptions = options.tree; + var simpleDataOptions = treeOptions.data.simpleData; var tableId = options.id; tableData = tableData || table.cache[tableId]; - return flatToTree(tableData, treeOptions.data.simpleData.idKey, treeOptions.data.simpleData.pIdKey, treeOptions.data.key.children) + return flatToTree(tableData, simpleDataOptions.idKey, simpleDataOptions.pIdKey, treeOptions.data.key.children, simpleDataOptions.rootPId) } Class.prototype.treeToFlat = function (tableData, parentId, parentIndex) { @@ -373,6 +377,7 @@ layui.define(['table'], function (exports) { item1[LAY_DATA_INDEX_HISTORY] = item1[LAY_DATA_INDEX]; item1[LAY_PARENT_INDEX] = parentIndex = parentIndex || ''; var dataIndex = item1[LAY_DATA_INDEX] = (parentIndex ? parentIndex + '-' : '') + i1; + dataIndex.indexOf('-') !== -1 && (table.cache[tableId][dataIndex] = item1); that.initData(item1[childrenKey] || [], dataIndex); }); @@ -399,11 +404,10 @@ layui.define(['table'], function (exports) { // 后续调优:对已经展开的节点进行展开和已经关闭的节点进行关闭应该做优化减少不必要的代码执行 todo var isToggle = layui.type(expandFlag) !== 'boolean'; - // var LAY_EXPAND = (layui.type(expandFlag) === 'boolean' ? expandFlag : !trData['LAY_EXPAND']); - var LAY_EXPAND = isToggle ? !trData['LAY_EXPAND'] : expandFlag; - var retValue = trData[isParentKey] ? LAY_EXPAND : null; + var trExpand = isToggle ? !trData[LAY_EXPAND] : expandFlag; + var retValue = trData[isParentKey] ? trExpand : null; - if (callbackFlag && LAY_EXPAND != trData['LAY_EXPAND'] && (!trData['LAY_ASYNC_STATUS'] || trData['LAY_ASYNC_STATUS'] === 'local')) { + if (callbackFlag && trExpand != trData[LAY_EXPAND] && (!trData['LAY_ASYNC_STATUS'] || trData['LAY_ASYNC_STATUS'] === 'local')) { var beforeExpand = treeOptions.callback.beforeExpand; if (layui.type(beforeExpand) === 'function') { if (beforeExpand(tableId, trData, expandFlag) === false) { @@ -412,28 +416,28 @@ layui.define(['table'], function (exports) { } } - var LAY_HAS_EXPANDED = trData['LAY_HAS_EXPANDED']; // 展开过,包括异步加载 + var trExpanded = trData[LAY_HAS_EXPANDED]; // 展开过,包括异步加载 // 找到表格中的同类节点(需要找到lay-data-index一致的所有行) var trsElem = tableViewElem.find('tr[lay-data-index="' + trIndex + '"]'); // 处理折叠按钮图标 var flexIconElem = trsElem.find('.layui-table-tree-flexIcon'); - flexIconElem.html(LAY_EXPAND ? treeOptions.view.flexIconOpen : treeOptions.view.flexIconClose) + flexIconElem.html(trExpand ? treeOptions.view.flexIconOpen : treeOptions.view.flexIconClose) trData[isParentKey] && flexIconElem.css('visibility', 'visible'); // 处理节点图标 if (treeOptions.view.showIcon && trData[isParentKey] && !trData.icon && !treeOptions.view.icon) { var nodeIconElem = trsElem.find('.layui-table-tree-nodeIcon'); - nodeIconElem.html(LAY_EXPAND ? treeOptions.view.iconOpen : treeOptions.view.iconClose); + nodeIconElem.html(trExpand ? treeOptions.view.iconOpen : treeOptions.view.iconClose); } var childNodes = trData[treeOptions.data.key.children] || []; // 测试用后续需要改成子节点的字段名称 // 处理子节点展示与否 - if (LAY_EXPAND) { + if (trExpand) { // 展开 - if (LAY_HAS_EXPANDED) { // 已经展开过 - if (LAY_EXPAND == trData['LAY_EXPAND']) { // 已经和当前的状态一样,是否有优化的空间,要注意直接方法调用级联展开和触发和不是级联的情况下的区别 + if (trExpanded) { // 已经展开过 + if (trExpand == trData[LAY_EXPAND]) { // 已经和当前的状态一样,是否有优化的空间,要注意直接方法调用级联展开和触发和不是级联的情况下的区别 } - trData['LAY_EXPAND'] = LAY_EXPAND; + trData[LAY_EXPAND] = trExpand; tableViewElem.find(childNodes.map(function (value, index, array) { return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' @@ -442,7 +446,7 @@ layui.define(['table'], function (exports) { if (sonSign && !isToggle) { // 非状态切换的情况下 // 级联展开子节点 expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); - } else if (item1.LAY_EXPAND) { + } else if (item1[LAY_EXPAND]) { // 级联展开 expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, true); } @@ -511,8 +515,8 @@ layui.define(['table'], function (exports) { }); return retValue; } - trData['LAY_EXPAND'] = LAY_EXPAND; - LAY_HAS_EXPANDED = trData['LAY_HAS_EXPANDED'] = true; + trData[LAY_EXPAND] = trExpand; + trExpanded = trData[LAY_HAS_EXPANDED] = true; if (childNodes.length) { // 判断是否需要排序 if (options.initSort && !options.url) { @@ -569,9 +573,9 @@ layui.define(['table'], function (exports) { } } } else { - if (LAY_EXPAND == trData['LAY_EXPAND']) { + if (trExpand == trData[LAY_EXPAND]) { } - trData['LAY_EXPAND'] = LAY_EXPAND; + trData[LAY_EXPAND] = trExpand; // 折叠 if (sonSign && !isToggle) { // 非状态切换的情况下 layui.each(childNodes, function (i1, item1) { @@ -610,9 +614,35 @@ layui.define(['table'], function (exports) { if (layui.type(expandFlag) !== 'boolean') { return hint.error('expandAll的展开状态参数只接收true/false') } - layui.each(table.cache[id], function (i1, item1) { - treeTable.expandNode(id, item1['LAY_DATA_INDEX'], expandFlag, true); - }) + // 调用expandNode一个个去处理会有性能问题重新实现该方法 + // layui.each(table.cache[id], function (i1, item1) { + // treeTable.expandNode(id, item1['LAY_DATA_INDEX'], expandFlag, true); + // }) + var that = getThisTable(id); + var options = that.getOptions(); + var treeOptions = options.tree; + + if (!expandFlag) { + // 关闭所有 + // 将所有已经打开的节点的状态设置为关闭, + that.updateStatus(null, {LAY_EXPAND: false}); // 只处理当前页,如果需要处理全部表格,需要用treeTable.updateStatus + // 隐藏所有非顶层的节点 + options.elem.next().find('tbody tr[data-level!="0"]').addClass('layui-hide'); + // 处理顶层节点的图标 + var trLevel0 = options.elem.next().find('tbody tr[data-level="0"]'); + trLevel0.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconClose); + trLevel0.find('.layui-table-tree-nodeIcon').html(treeOptions.view.iconClose); + + treeTable.resize(); + } else { + // 展开所有 + // 先判断是否全部打开过了 + + // 如果是异步加载子节点模式 如何处理 + // 如果有部分节点未打开过,也需要重新 + // 如果全部节点已经都打开过,就可以简单处理跟隐藏所有节点反操作 + } + } Class.prototype.renderTreeTable = function (tableView, level, sonSign) { @@ -658,7 +688,7 @@ layui.define(['table'], function (exports) { return; } var trData = treeTableThat.getNodeDataByIndex(trIndex); - if (trData.LAY_EXPAND) { + if (trData[LAY_EXPAND]) { // 需要展开 dataExpand[trIndex] = true; } @@ -838,7 +868,7 @@ layui.define(['table'], function (exports) { // 处理del方法 obj.del = function () { - treeTable.removeNode(tableId, trIndex); + treeTable.removeNode(tableId, trData); } } @@ -870,25 +900,20 @@ layui.define(['table'], function (exports) { } // 删除数据 - treeTable.removeNode = function (id, index) { + treeTable.removeNode = function (id, node) { var that = getThisTable(id); var options = that.getOptions(); var treeOptions = options.tree; var tableView = options.elem.next(); - if (!layui.isArray(index)) { - index = [index]; - } var delNode; var indexArr = []; - layui.each(index, function (index, indexValue) { - delNode = that.getNodeDataByIndex(indexValue, false, 'delete'); - var nodeP = that.getNodeDataByIndex(delNode[LAY_PARENT_INDEX]); - that.updateCheckStatus(nodeP, true);// 删除节点接近取消选择 todo - var delNodesFlat = that.treeToFlat([delNode], delNode[treeOptions.data.simpleData.pIdKey], delNode[LAY_PARENT_INDEX]); - layui.each(delNodesFlat, function (i2, item2) { - indexArr.push('tr[lay-data-index="' + item2[LAY_DATA_INDEX] + '"]'); - }) - }); + delNode = that.getNodeDataByIndex(layui.type(node) === 'string' ? node : node[LAY_DATA_INDEX], false, 'delete'); + var nodeP = that.getNodeDataByIndex(delNode[LAY_PARENT_INDEX]); + that.updateCheckStatus(nodeP, true); + var delNodesFlat = that.treeToFlat([delNode], delNode[treeOptions.data.simpleData.pIdKey], delNode[LAY_PARENT_INDEX]); + layui.each(delNodesFlat, function (i2, item2) { + indexArr.push('tr[lay-data-index="' + item2[LAY_DATA_INDEX] + '"]'); + }) tableView.find(indexArr.join(',')).remove(); // 删除行 // 重新整理数据 @@ -916,9 +941,10 @@ layui.define(['table'], function (exports) { * @param {String|Number} parentIndex 指定的父节点,如果增加根节点,请设置 parentIndex 为 null 即可 * @param {Number} index:Number 新节点插入的位置(从 0 开始)index = -1(默认) 时,插入到最后 * @param {Object|Array} newNodes 新增的节点,单个或者多个 + * @param {Boolean} focus 新增的节点,单个或者多个 * @return {Array} 新增的节点 * */ - treeTable.addNodes = function (id, parentIndex, index, newNodes) { + treeTable.addNodes = function (id, parentIndex, index, newNodes, focus) { var that = getThisTable(id); var options = that.getOptions(); var treeOptions = options.tree; @@ -1019,7 +1045,7 @@ layui.define(['table'], function (exports) { // 删除已经存在的同级节点以及他们的子节点,并且把中间节点的已展开过的状态设置为false that.updateStatus(childrenNodes, function (d) { if (d[isParentKey]) { - d['LAY_HAS_EXPANDED'] = false; + d[LAY_HAS_EXPANDED] = false; } }); var childrenNodesFlat = that.treeToFlat(childrenNodes); @@ -1029,10 +1055,16 @@ layui.define(['table'], function (exports) { tableData = that.initData(); // 去掉父节点的已经展开过的状态,重新执行一次展开的方法 - parentNode['LAY_HAS_EXPANDED'] = false; + parentNode[LAY_HAS_EXPANDED] = false; parentNode['LAY_ASYNC_STATUS'] = 'local'; // 转为本地数据,应该规定异步加载子节点的时候addNodes的规则 expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + parentIndex + '"]')}, true) } + that.updateCheckStatus(parentNode, true); + treeTable.resize(id); + if (focus) { + // 滚动到第一个新增的节点 + tableViewElem.find(ELEM_MAIN).find('tr[lay-data-index="'+newNodes[0][LAY_DATA_INDEX]+'"]').get(0).scrollIntoViewIfNeeded(); + } return newNodes; } @@ -1136,6 +1168,7 @@ layui.define(['table'], function (exports) { var statusChecked = {}; statusChecked[table.config.checkName] = false; that.updateStatus(null, statusChecked); // 取消其他的选中状态 + // treeTable.updateStatus(tableId, statusChecked); table.cache[tableId][trIndex][table.config.checkName] = obj.checked; } }) @@ -1194,13 +1227,17 @@ layui.define(['table'], function (exports) { dataP[LAY_CHECKBOX_HALF] = false; // 先设置为非半选,是否为半选又下面逻辑判断 if (checked) { // 为真需要判断子节点的情况 - layui.each(dataP[childrenKey], function (index, item) { - if (!item[checkName]) { // 只要有一个子节点为false - checked = false; - dataP[LAY_CHECKBOX_HALF] = true; - return true; // 跳出循环 - } - }); + if (!dataP[childrenKey].length) { + checked = false; + } else { + layui.each(dataP[childrenKey], function (index, item) { + if (!item[checkName]) { // 只要有一个子节点为false + checked = false; + dataP[LAY_CHECKBOX_HALF] = true; + return true; // 跳出循环 + } + }); + } } else { // 判断是否为半选 layui.each(dataP[childrenKey], function (index, item) { From 9bb0331c2f62e8d71b3b13904d20aa6dbe8f60d2 Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Mon, 17 Apr 2023 18:57:30 +0800 Subject: [PATCH 13/15] =?UTF-8?q?treeTable=E4=B8=80=E4=BA=9B=E5=B0=8F?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/treeTable.js | 61 +++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index 187b95e2..53b6da06 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -329,9 +329,15 @@ layui.define(['table'], function (exports) { // 删除 if (tableCache) { // 同步cache - tableCache.splice(tableCache.findIndex(function (value) { - return value[LAY_DATA_INDEX] === index; - }), 1) + // tableCache.splice(tableCache.findIndex(function (value) { + // return value[LAY_DATA_INDEX] === index; + // }), 1); + layui.each(tableCache, function (i1, item1) { + if (item1[LAY_DATA_INDEX] === index) { + tableCache.splice(i1, 1); + return true; + } + }) } return (i ? dataRet[childrenKey] : dataRet).splice(indexArr[i], 1)[0]; } else { @@ -435,10 +441,7 @@ layui.define(['table'], function (exports) { if (trExpand) { // 展开 if (trExpanded) { // 已经展开过 - if (trExpand == trData[LAY_EXPAND]) { // 已经和当前的状态一样,是否有优化的空间,要注意直接方法调用级联展开和触发和不是级联的情况下的区别 - } trData[LAY_EXPAND] = trExpand; - tableViewElem.find(childNodes.map(function (value, index, array) { return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(',')).removeClass('layui-hide'); @@ -573,8 +576,6 @@ layui.define(['table'], function (exports) { } } } else { - if (trExpand == trData[LAY_EXPAND]) { - } trData[LAY_EXPAND] = trExpand; // 折叠 if (sonSign && !isToggle) { // 非状态切换的情况下 @@ -621,26 +622,59 @@ layui.define(['table'], function (exports) { var that = getThisTable(id); var options = that.getOptions(); var treeOptions = options.tree; + var tableView = options.elem.next(); if (!expandFlag) { // 关闭所有 // 将所有已经打开的节点的状态设置为关闭, that.updateStatus(null, {LAY_EXPAND: false}); // 只处理当前页,如果需要处理全部表格,需要用treeTable.updateStatus // 隐藏所有非顶层的节点 - options.elem.next().find('tbody tr[data-level!="0"]').addClass('layui-hide'); + tableView.find('tbody tr[data-level!="0"]').addClass('layui-hide'); // 处理顶层节点的图标 - var trLevel0 = options.elem.next().find('tbody tr[data-level="0"]'); + var trLevel0 = tableView.find('tbody tr[data-level="0"]'); trLevel0.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconClose); trLevel0.find('.layui-table-tree-nodeIcon').html(treeOptions.view.iconClose); treeTable.resize(); } else { // 展开所有 - // 先判断是否全部打开过了 + if (treeOptions.async.enable) { + // 存在异步加载 + + } else { + // 先判断是否全部打开过了 + var tableDataFlat = treeTable.getData(id, true); + var isAllExpanded = true; + layui.each(tableDataFlat, function (i1, item1) { + if (!item1[LAY_HAS_EXPANDED]) { + isAllExpanded = false; + return true; + } + }) + // 如果全部节点已经都打开过,就可以简单处理跟隐藏所有节点反操作 + if (isAllExpanded) { + that.updateStatus(null, {LAY_EXPAND: true}); // 只处理当前页,如果需要处理全部表格,需要用treeTable.updateStatus + // 隐藏所有非顶层的节点 + tableView.find('tbody tr[data-level!="0"]').removeClass('layui-hide'); + // 处理顶层节点的图标 + // var trLevel0 = tableView.find('tbody tr[data-level="0"]'); + tableView.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconOpen); + tableView.find('.layui-table-tree-nodeIcon').html(treeOptions.view.iconOpen); + + treeTable.resize(); + } else { + debugger; + // 如果有未打开过的父节点,将内容全部生成 + that.updateStatus(null, {LAY_EXPAND: true, LAY_HAS_EXPANDED: true}); + var trsAll = table.getTrHtml(id, tableDataFlat); + + } + + } + // 如果是异步加载子节点模式 如何处理 // 如果有部分节点未打开过,也需要重新 - // 如果全部节点已经都打开过,就可以简单处理跟隐藏所有节点反操作 } } @@ -674,7 +708,6 @@ layui.define(['table'], function (exports) { var dataExpand = {}; // 记录需要展开的数据 var nameKey = treeOptions.data.key.name; var indent = treeOptions.view.indent || 14; - // 后期需要添加一个配置来决定展开的图标放在哪个字段 layui.each(tableView.find('td[data-field="' + nameKey + '"]'), function (index, item) { item = $(item); var trElem = item.closest('tr'); @@ -1063,7 +1096,7 @@ layui.define(['table'], function (exports) { treeTable.resize(id); if (focus) { // 滚动到第一个新增的节点 - tableViewElem.find(ELEM_MAIN).find('tr[lay-data-index="'+newNodes[0][LAY_DATA_INDEX]+'"]').get(0).scrollIntoViewIfNeeded(); + tableViewElem.find(ELEM_MAIN).find('tr[lay-data-index="' + newNodes[0][LAY_DATA_INDEX] + '"]').get(0).scrollIntoViewIfNeeded(); } return newNodes; } From aafbfcc978608755ca9908de88dadf0c5b1297bc Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Tue, 18 Apr 2023 15:49:00 +0800 Subject: [PATCH 14/15] =?UTF-8?q?treeTable=E4=B8=80=E4=BA=9B=E5=B0=8F?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=8C=E6=96=B0=E5=A2=9EcheckNode=E5=92=8C?= =?UTF-8?q?checkAllNodes=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/treeTable.js | 213 ++++++++++++++++++++++++--------------- 1 file changed, 133 insertions(+), 80 deletions(-) diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index 53b6da06..0631ad5b 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -100,6 +100,17 @@ layui.define(['table'], function (exports) { that.render(); }; + var updateCache = function (id, childrenKey, data) { + var tableCache = table.cache[id]; + layui.each(data || tableCache, function (index, item) { + var itemDataIndex = item[LAY_DATA_INDEX]; + if (itemDataIndex.indexOf('-') !== -1) { + tableCache[itemDataIndex] = item + } + item[childrenKey] && updateCache(id, childrenKey, item[childrenKey]); + }) + } + Class.prototype.init = function () { var that = this; var options = that.config; @@ -153,17 +164,6 @@ layui.define(['table'], function (exports) { that.initData(options.data); } - var updateCache = function (data) { - var tableCache = table.cache[id]; - layui.each(data || tableCache, function (index, item) { - var itemDataIndex = item[LAY_DATA_INDEX]; - if (itemDataIndex.indexOf('-') !== -1) { - tableCache[itemDataIndex] = item - } - item[childrenKey] && updateCache(item[childrenKey]); - }) - } - options.done = function () { var args = arguments; var doneThat = this; @@ -173,7 +173,7 @@ layui.define(['table'], function (exports) { LAY_HAS_EXPANDED: false // 去除已经打开过的状态 }); // 更新cache中的内容 将子节点也存到cache中 - updateCache(); + updateCache(id, childrenKey); // 更新全选框的状态 var layTableAllChooseElem = tableView.find('[name="layTableCheckbox"][lay-filter="layTableAllChoose"]'); if (layTableAllChooseElem.length) { @@ -383,10 +383,11 @@ layui.define(['table'], function (exports) { item1[LAY_DATA_INDEX_HISTORY] = item1[LAY_DATA_INDEX]; item1[LAY_PARENT_INDEX] = parentIndex = parentIndex || ''; var dataIndex = item1[LAY_DATA_INDEX] = (parentIndex ? parentIndex + '-' : '') + i1; - dataIndex.indexOf('-') !== -1 && (table.cache[tableId][dataIndex] = item1); that.initData(item1[childrenKey] || [], dataIndex); }); + parentIndex || updateCache(tableId, childrenKey); + return data; } @@ -637,6 +638,8 @@ layui.define(['table'], function (exports) { treeTable.resize(); } else { + console.log('目前暂时不支持展开全部'); + return ; // 展开所有 if (treeOptions.async.enable) { // 存在异步加载 @@ -663,7 +666,6 @@ layui.define(['table'], function (exports) { treeTable.resize(); } else { - debugger; // 如果有未打开过的父节点,将内容全部生成 that.updateStatus(null, {LAY_EXPAND: true, LAY_HAS_EXPANDED: true}); var trsAll = table.getTrHtml(id, tableDataFlat); @@ -1197,12 +1199,7 @@ layui.define(['table'], function (exports) { if (tableView.hasClass('layui-table-tree')) { updateObjParams(obj); - var trIndex = obj.index; - var statusChecked = {}; - statusChecked[table.config.checkName] = false; - that.updateStatus(null, statusChecked); // 取消其他的选中状态 - // treeTable.updateStatus(tableId, statusChecked); - table.cache[tableId][trIndex][table.config.checkName] = obj.checked; + checkNode.call(that, obj.tr, obj.checked) } }) @@ -1288,6 +1285,84 @@ layui.define(['table'], function (exports) { return dataRet } + var checkNode = function (trElem, checked, callbackFlag) { + var that = this; + var options = that.getOptions(); + var tableId = options.id; + var tableView = options.elem.next(); + var inputElem = (trElem.length ? trElem : tableView).find('.laytable-cell-radio, .laytable-cell-checkbox').children('input').last(); + // 判断是单选还是多选 不应该同时存在radio列和checkbox列 + var isRadio = inputElem.attr('type') === 'radio'; + + if (callbackFlag) { + // 如果需要触发事件可以简单的触发对应节点的click事件 + if (isRadio) { + // 单选只能选中或者切换其他的不能取消选中 后续看是否有支持的必要 todo + if (checked && !inputElem.prop('checked')) { + inputElem.next().click(); + } + } else { + if (layui.type(checked) === 'boolean') { + if (inputElem.prop('checked') !== checked) { + // 如果当前已经是想要修改的状态则不做处理 + inputElem.next().click(); + } + } else { + // 切换 + inputElem.next().click(); + } + } + } else { + var trData = that.getNodeDataByIndex(trElem.attr('data-index')); + var checkName = table.config.checkName; + // 如果不触发事件应该有一个方法可以更新数据以及页面的节点 + if (isRadio) { + if (!trData) { + // 单选必须是一个存在的行 + return; + } + var statusChecked = {}; + statusChecked[checkName] = false; + // that.updateStatus(null, statusChecked); // 取消其他的选中状态 + that.updateStatus(null, function (d) { + if (d[checkName]) { + d[checkName] = false; + form.render(tableView.find('tr[lay-data-index="' + d[LAY_DATA_INDEX] + '"] input[type="radio"][lay-type="layTableRadio"]').prop('checked', false)); + } + }); // 取消其他的选中状态 + trData[checkName] = checked; + form.render(trElem.find('input[type="radio"][lay-type="layTableRadio"]').prop('checked', checked)); + } else { + var isParentKey = options.tree.data.key.isParent; + // 切换只能用到单条,全选到这一步的时候应该是一个确定的状态 + checked = layui.type(checked) === 'boolean' ? checked : !trData[checkName]; // 状态切换,如果遇到不可操作的节点待处理 todo + // 全选或者是一个父节点,将子节点的状态同步为当前节点的状态 + if (!trData || trData[isParentKey]) { + // 处理不可操作的信息 + var checkedStatusFn = function (d) { + if (!d[table.config.disabledName]) { // 节点不可操作的不处理 + d[checkName] = checked; + d[LAY_CHECKBOX_HALF] = false; + } + } + + var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatusFn); + form.render(tableView.find(trs.map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)'; + }).join(',')).prop({checked: checked, indeterminate: false})); + } + var trDataP; + // 更新父节点以及更上层节点的状态 + if (trData && trData[LAY_PARENT_INDEX]) { + // 找到父节点,然后判断父节点的子节点是否全部选中 + trDataP = that.getNodeDataByIndex(trData[LAY_PARENT_INDEX]); + } + + return that.updateCheckStatus(trDataP, checked); + } + } + } + // 多选 treeTable.on('checkbox', function (obj) { var options = obj.config; @@ -1298,70 +1373,48 @@ layui.define(['table'], function (exports) { if (tableView.hasClass('layui-table-tree')) { updateObjParams(obj); var checked = obj.checked; - var treeOptions = options.tree; - var isParentKey = treeOptions.data.key.isParent; - var childrenKey = treeOptions.data.key.children; - var trIndex = obj.index; - var checkName = table.config.checkName; - // 修改当前节点的信息 - var trData = that.getNodeDataByIndex(trIndex); - // trData[checkName] = checked; - // 如果是一个父节点,将子节点的状态同步为当前节点的状态,并且注意更深层次的 - if (obj.type === 'all' || trData[isParentKey]) { - var checkedStatus = {}; - checkedStatus[checkName] = checked; - checkedStatus[LAY_CHECKBOX_HALF] = false; - - // 处理不可操作的信息 - var checkedStatusFn = function (d) { - if (!d[table.config.disabledName]) { // 节点不可操作的不处理 - d[checkName] = checked; - d[LAY_CHECKBOX_HALF] = false; - } - } - - // var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatus); - var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatusFn); - form.render(tableView.find(trs.map(function (value) { - return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)'; - }).join(',')).prop({checked: checked, indeterminate: false})); - } - var trDataP; - // 更新父节点以及更上层节点的状态 - if (trData && trData[LAY_PARENT_INDEX]) { - // 找到父节点,然后判断父节点的子节点是否全部选中 - trDataP = that.getNodeDataByIndex(trData[LAY_PARENT_INDEX]); - // var trsP = that.updateParentCheckStatus(trDataP, checked); - // layui.each(trsP, function (indexP, itemP) { - // form.render(tableView.find('tr[lay-data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)').prop({ - // checked: itemP[checkName], - // indeterminate: itemP[LAY_CHECKBOX_HALF] - // })) - // }) - } - - obj.isAll = that.updateCheckStatus(trDataP, checked); - - // 全选图标的状态更新 - // obj.isAll = true; - // var isIndeterminate = false; - // layui.each(table.cache[tableId], function (i1, item1) { - // if (item1[checkName] || item1[LAY_CHECKBOX_HALF]) { - // isIndeterminate = true; - // } - // if (!item1[checkName]) { - // obj.isAll = false; - // } - // }) - // isIndeterminate = isIndeterminate && !obj.isAll; - // form.render(tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({ - // 'checked': obj.isAll, - // indeterminate: isIndeterminate - // })); + obj.isAll = checkNode.call(that, obj.tr, checked); } }) + /** + * 勾选或取消勾选单个节点 + * @param {String} id 树表id + * @param {Object|String} node 节点 + * @param {Boolean} checked 选中或取消 + * @param {Boolean} callbackFlag 是否触发事件回调 + * */ + treeTable.checkNode = function (id, node, checked, callbackFlag) { + var that = getThisTable(id); + var options = that.getOptions(); + var tableView = options.elem.next(); + + var dataIndex = layui.type(node) === 'string' ? node : node[LAY_DATA_INDEX]; + // 判断是否在当前页面中 + var nodeData = that.getNodeDataByIndex(dataIndex); + if (!nodeData) { + // 目前只能处理当前页的数据 + return; + } + // 判断是否展开过 + var trElem = tableView.find('tr[lay-data-index="' + dataIndex + '"]'); + if (!trElem.length) { + // 如果还没有展开没有渲染的要先渲染出来 + treeTable.expandNode(id, nodeData[LAY_PARENT_INDEX], true); + trElem = tableView.find('tr[lay-data-index="' + dataIndex + '"]'); + } + checkNode.call(that, trElem, checked, callbackFlag); + } + + treeTable.checkAllNodes = function (id, checked) { + var that = getThisTable(id); + var options = that.getOptions(); + var tableView = options.elem.next(); + + checkNode.call(that, tableView.find('tr[data-index="NONE"]'), !!checked) + } + /** * 获得数据 * @param {String} id 表格id From 41a000f39c1002e70c3fef65f7996b8b143e4329 Mon Sep 17 00:00:00 2001 From: sunxiaobin89 <285584806@qq.com> Date: Tue, 18 Apr 2023 16:25:06 +0800 Subject: [PATCH 15/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8DtreeTable=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E5=B0=8F=E4=BF=AE=E6=94=B9=EF=BC=8C=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=BF=9B=E5=85=A5=E8=A1=8C=E4=BA=8B=E4=BB=B6=E4=B8=AD=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=9A=84setRowChecked=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E6=96=B9=E4=BE=BF=E5=9C=A8=E4=B8=80=E4=BA=9B=E5=9C=BA=E5=90=88?= =?UTF-8?q?=E4=BE=BF=E6=8D=B7=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/treeTable.js | 47 +++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index 0631ad5b..019b010b 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -639,7 +639,7 @@ layui.define(['table'], function (exports) { treeTable.resize(); } else { console.log('目前暂时不支持展开全部'); - return ; + return; // 展开所有 if (treeOptions.async.enable) { // 存在异步加载 @@ -905,6 +905,11 @@ layui.define(['table'], function (exports) { obj.del = function () { treeTable.removeNode(tableId, trData); } + + // 处理setRowChecked + obj.setRowChecked = function (checked) { + treeTable.checkNode(tableId, trData, checked); + } } // 更新数据 @@ -1295,21 +1300,29 @@ layui.define(['table'], function (exports) { var isRadio = inputElem.attr('type') === 'radio'; if (callbackFlag) { + var triggerEvent = function () { + var fn = function (event) { + layui.stope(event); + } + inputElem.parent().on('click', fn); // 添加临时的阻止冒泡事件 + inputElem.next().click(); + inputElem.parent().off('click', fn); + } // 如果需要触发事件可以简单的触发对应节点的click事件 if (isRadio) { // 单选只能选中或者切换其他的不能取消选中 后续看是否有支持的必要 todo if (checked && !inputElem.prop('checked')) { - inputElem.next().click(); + triggerEvent() } } else { if (layui.type(checked) === 'boolean') { if (inputElem.prop('checked') !== checked) { // 如果当前已经是想要修改的状态则不做处理 - inputElem.next().click(); + triggerEvent() } } else { // 切换 - inputElem.next().click(); + triggerEvent() } } } else { @@ -1337,20 +1350,20 @@ layui.define(['table'], function (exports) { // 切换只能用到单条,全选到这一步的时候应该是一个确定的状态 checked = layui.type(checked) === 'boolean' ? checked : !trData[checkName]; // 状态切换,如果遇到不可操作的节点待处理 todo // 全选或者是一个父节点,将子节点的状态同步为当前节点的状态 - if (!trData || trData[isParentKey]) { - // 处理不可操作的信息 - var checkedStatusFn = function (d) { - if (!d[table.config.disabledName]) { // 节点不可操作的不处理 - d[checkName] = checked; - d[LAY_CHECKBOX_HALF] = false; - } + // if (!trData || trData[isParentKey]) { + // 处理不可操作的信息 + var checkedStatusFn = function (d) { + if (!d[table.config.disabledName]) { // 节点不可操作的不处理 + d[checkName] = checked; + d[LAY_CHECKBOX_HALF] = false; } - - var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatusFn); - form.render(tableView.find(trs.map(function (value) { - return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)'; - }).join(',')).prop({checked: checked, indeterminate: false})); } + + var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatusFn); + form.render(tableView.find(trs.map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)'; + }).join(',')).prop({checked: checked, indeterminate: false})); + // } var trDataP; // 更新父节点以及更上层节点的状态 if (trData && trData[LAY_PARENT_INDEX]) { @@ -1383,7 +1396,7 @@ layui.define(['table'], function (exports) { * @param {String} id 树表id * @param {Object|String} node 节点 * @param {Boolean} checked 选中或取消 - * @param {Boolean} callbackFlag 是否触发事件回调 + * @param {Boolean} [callbackFlag] 是否触发事件回调 * */ treeTable.checkNode = function (id, node, checked, callbackFlag) { var that = getThisTable(id);