diff --git a/src/modules/table.js b/src/modules/table.js index 1712f5d7..62844c8d 100644 --- a/src/modules/table.js +++ b/src/modules/table.js @@ -1459,9 +1459,6 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ tr.addClass(ELEM_CLICK).siblings('tr').removeClass(ELEM_CLICK); } - // 仅设置样式状态 - if(opts.selectedStyle || selectedStyle) return; - // 同步数据选中属性值 var thisData = table.cache[that.key]; @@ -1475,13 +1472,28 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){ }); // 若存在复选框或单选框,则标注选中样式 - tr.find('input[lay-type="'+ ({ + var checkedElem = tr.find('input[lay-type="'+ ({ radio: 'layTableRadio', checkbox: 'layTableCheckbox' }[opts.type] || 'checkbox') +'"]').prop('checked', opts.checked); that.syncCheckAll(); that.renderForm(opts.type); + + // 仅设置样式状态 + if(opts.selectedStyle || selectedStyle) return; + + layui.event.call( + checkedElem[0], + MOD_NAME, opts.type + '('+ options.elem.attr('lay-filter') +')', + that.commonMember.call(checkedElem[0], { + checked: opts.checked, + type: opts.index === 'all' ? 'all' : 'one', + getCol: function(){ // 获取当前列的表头配置信息 + return that.col(checkedElem.closest('td').data('key')); + } + }) + ); }; // 数据排序 diff --git a/src/modules/treeTable.js b/src/modules/treeTable.js index c3bd6958..92a90c84 100644 --- a/src/modules/treeTable.js +++ b/src/modules/treeTable.js @@ -10,7 +10,6 @@ layui.define(['table'], function (exports) { var form = layui.form; var table = layui.table; var hint = layui.hint(); - var timer = {}; // 记录定时器 index // api var treeTable = { @@ -106,9 +105,13 @@ layui.define(['table'], function (exports) { var updateOptions = function (id, options, reload) { var that = getThisTable(id); - var thatOptionsTemp = $.extend(true, {} , that.getOptions(), options); + reload === 'reloadData' || (that.status = { // 用于记录一些状态信息 + expand: {} // 折叠状态 + }); + var thatOptionsTemp = $.extend(true, {}, that.getOptions(), options); var treeOptions = thatOptionsTemp.tree; var childrenKey = treeOptions.customName.children; + var idKey = treeOptions.customName.id; // 处理属性 delete options.hasNumberCol; delete options.hasChecboxCol; @@ -141,6 +144,10 @@ layui.define(['table'], function (exports) { if (treeOptions.data.isSimpleData && !treeOptions.async.enable) { // 异步加载和 isSimpleData 不应该一起使用 retData[dataName] = that.flatToTree(retData[dataName]); } + // 处理节点状态 + updateStatus(retData[dataName], function (item) { + item[LAY_EXPAND] = that.status.expand[item[idKey]] + }, childrenKey); if (parseDataThat.autoSort && parseDataThat.initSort && parseDataThat.initSort.type) { layui.sort(retData[dataName], parseDataThat.initSort.field, parseDataThat.initSort.type === 'desc', true) @@ -221,6 +228,7 @@ layui.define(['table'], function (exports) { name: "name", // 节点数据保存节点名称的属性名称 id: "id", // 唯一标识的属性名称 pid: "parentId", // 父节点唯一标识的属性名称 + icon: "icon", // 图标的属性名称 }, view: { indent: 14, // 层级缩进量 @@ -270,14 +278,18 @@ layui.define(['table'], function (exports) { // 创建一个空的 nodes 对象,用于保存所有的节点 var nodes = {}; // 遍历所有节点,将其加入 nodes 对象中 + var idTemp = ''; layui.each(flatArr, function (index, item) { - nodes[item[idKey]] = $.extend({}, item); - nodes[item[idKey]][childrenKey] = []; + idTemp = idKey + item[idKey]; + nodes[idTemp] = $.extend({}, item); + nodes[idTemp][childrenKey] = []; }) // 遍历所有节点,将其父子关系加入 nodes 对象 + var pidTemp = ''; layui.each(nodes, function (index, item) { - if (item[pIdKey] && nodes[item[pIdKey]]) { - nodes[item[pIdKey]][childrenKey].push(item); + pidTemp = idKey + item[pIdKey]; + if (pidTemp && nodes[pidTemp]) { + nodes[pidTemp][childrenKey].push(item); } }) // 返回顶层节点 @@ -319,6 +331,95 @@ layui.define(['table'], function (exports) { return flat; } + // 通过当前行数据返回 treeNode 信息 + Class.prototype.getTreeNode = function (data) { + var that = this; + if (!data) { + return hint.error('找不到节点数据'); + } + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + var customName = treeOptions.customName; + + var treeNode = { + data: data, + dataIndex: data[LAY_DATA_INDEX], + getParentNode: function () { + return that.getNodeByIndex(data[LAY_PARENT_INDEX]) + }, + } + // 带上一些常用的方法 + + return treeNode; + } + + // 通过 index 返回节点信息 + Class.prototype.getNodeByIndex = function (index) { + var that = this; + var treeNodeData = that.getNodeDataByIndex(index); + if (!treeNodeData) { + return hint.error('找不到节点数据'); + } + var options = that.getOptions(); + var treeOptions = options.tree; + var customName = treeOptions.customName; + var parentKey = customName.parent; + var tableId = options.id; + + var treeNode = { + data: treeNodeData, + dataIndex: treeNodeData[LAY_DATA_INDEX], + getParentNode: function () { + return that.getNodeByIndex(treeNodeData[LAY_PARENT_INDEX]) + }, + update: function (data) { + return treeTable.updateNode(tableId, index, data) + }, + remove: function () { + return treeTable.removeNode(tableId, index) + }, + expand: function (opts) { + return treeTable.expandNode(tableId, $.extend({}, opts, { + index: index + })) + }, + setChecked: function (opts) { + return treeTable.setRowChecked(tableId, $.extend({}, opts, { + index: index + })) + } + }; + + treeNode.dataIndex = index; + return treeNode; + } + + // 通过 id 获取节点信息 + Class.prototype.getNodeById = function (id) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var customName = treeOptions.customName; + var idKey = customName.id; + + // 通过 id 拿到数据的 dataIndex + var dataIndex = ''; + var tableDataFlat = treeTable.getData(options.id, true); + layui.each(tableDataFlat, function (i1, item1) { + if (item1[idKey] === id) { + dataIndex = item1[LAY_DATA_INDEX]; + return true; + } + }) + if (!dataIndex) { + return; + } + + // 用index + return that.getNodeByIndex(dataIndex); + } + // 通过index获取节点数据 Class.prototype.getNodeDataByIndex = function (index, clone, newValue) { var that = this; @@ -344,9 +445,6 @@ layui.define(['table'], function (exports) { // 删除 if (tableCache) { // 同步cache - // 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); @@ -414,7 +512,9 @@ layui.define(['table'], function (exports) { var debounceFn = (function () { var fn = {}; return function (tableId, func, wait) { - fn[tableId] = fn[tableId] || layui.debounce(func, wait); + if (!fn[tableId]) { + fn[tableId] = layui.debounce(func, wait); + } return fn[tableId]; } })() @@ -439,9 +539,6 @@ layui.define(['table'], function (exports) { var isToggle = layui.type(expandFlag) !== 'boolean'; var trExpand = isToggle ? !trData[LAY_EXPAND] : expandFlag; var retValue = trData[isParentKey] ? trExpand : null; - if (retValue === null) { - return retValue; - } if (callbackFlag && trExpand != trData[LAY_EXPAND] && (!trData[LAY_ASYNC_STATUS] || trData[LAY_ASYNC_STATUS] === 'local')) { var beforeExpand = treeOptions.callback.beforeExpand; @@ -461,9 +558,15 @@ layui.define(['table'], function (exports) { flexIconElem.html(trExpand ? treeOptions.view.flexIconOpen : treeOptions.view.flexIconClose) trData[isParentKey] && flexIconElem.css('visibility', 'visible'); // 处理节点图标 - treeOptions.view.showIcon && trsElem.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)') + treeOptions.view.showIcon && trsElem + .find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)') .html(trExpand ? treeOptions.view.iconOpen : treeOptions.view.iconClose); + treeTableThat.status.expand[trData[customName.id]] = trData[LAY_EXPAND] = trExpand; + if (retValue === null) { + return retValue; + } + var childNodes = trData[customName.children] || []; // 处理子节点展示与否 if (trExpand) { @@ -472,7 +575,6 @@ layui.define(['table'], function (exports) { trsElem.nextAll(childNodes.map(function (value, index, array) { return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(',')).removeClass(HIDE); - trData[LAY_EXPAND] = trExpand; layui.each(childNodes, function (i1, item1) { if (!item1[isParentKey]) { return; @@ -500,9 +602,24 @@ layui.define(['table'], function (exports) { } else { var asyncSetting = treeOptions.async || {}; var asyncUrl = asyncSetting.url || options.url; - // 提供一个能支持用户在获取子数据转换调用的回调,这样让子节点数据获取更加灵活 todo - if (asyncSetting.enable && trData[isParentKey] && asyncUrl && !trData[LAY_ASYNC_STATUS]) { + if (asyncSetting.enable && trData[isParentKey] && !trData[LAY_ASYNC_STATUS]) { trData[LAY_ASYNC_STATUS] = 'loading'; + flexIconElem.html(''); + + // 异步获取子节点数据成功之后处理方法 + var asyncSuccessFn = function (data) { + trData[LAY_ASYNC_STATUS] = 'success'; + trData[customName.children] = data; + treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX]) + expandNode(treeNode, true, isToggle ? false : sonSign, focus, callbackFlag); + } + + var format = asyncSetting.format; // 自定义数据返回方法 + if (layui.type(format) === 'function') { + format(trData, options, asyncSuccessFn); + return retValue; + } + var params = {}; // 参数 var data = $.extend(params, asyncSetting.where || options.where); @@ -524,8 +641,6 @@ layui.define(['table'], function (exports) { var asyncParseData = asyncSetting.parseData || options.parseData; var asyncResponse = asyncSetting.response || options.response; - // that.loading(); - flexIconElem.html('') $.ajax({ type: asyncType || 'get', url: asyncUrl, @@ -535,7 +650,6 @@ layui.define(['table'], function (exports) { jsonpCallback: asyncJsonpCallback, headers: asyncHeaders || {}, success: function (res) { - trData[LAY_ASYNC_STATUS] = 'success'; // 若有数据解析的回调,则获得其返回的数据 if (typeof asyncParseData === 'function') { res = asyncParseData.call(options, res) || res; @@ -547,10 +661,8 @@ layui.define(['table'], function (exports) { flexIconElem.html(''); // 事件 } else { - trData[customName.children] = res[asyncResponse.dataName]; - treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX]) // 正常返回 - expandNode(treeNode, true, isToggle ? false : sonSign, focus, callbackFlag); + asyncSuccessFn(res[asyncResponse.dataName]); } }, error: function (e, msg) { @@ -561,7 +673,6 @@ layui.define(['table'], function (exports) { }); return retValue; } - trData[LAY_EXPAND] = trExpand; trExpanded = trData[LAY_HAS_EXPANDED] = true; if (childNodes.length) { // 判断是否需要排序 @@ -608,9 +719,7 @@ layui.define(['table'], function (exports) { tableViewElem.find(ELEM_FIXR).find('tbody tr[lay-data-index="' + dataIndex + '"]').after(str2Obj.trs_fixed_r); // 初始化新增的节点中的内容 - layui.each(str2Obj, function (key, item) { - treeTableThat.renderTreeTable(item, dataLevelNew); - }) + treeTableThat.renderTreeTable(str2Obj.trs, dataLevelNew); if (sonSign && !isToggle) { // 非状态切换的情况下 // 级联展开/关闭子节点 @@ -627,7 +736,6 @@ layui.define(['table'], function (exports) { } } } else { - trData[LAY_EXPAND] = trExpand; // 关闭 if (sonSign && !isToggle) { // 非状态切换的情况下 layui.each(childNodes, function (i1, item1) { @@ -649,13 +757,15 @@ layui.define(['table'], function (exports) { }).join(',')).addClass(HIDE); } } - debounceFn(tableId, function () { + + + debounceFn('resize-' + tableId, function () { treeTable.resize(tableId); - }, 25)(); + }, 0)(); if (callbackFlag && trData[LAY_ASYNC_STATUS] !== 'loading') { var onExpand = treeOptions.callback.onExpand; - layui.type(onExpand) === 'function' && onExpand(tableId, trData, expandFlag); + layui.type(onExpand) === 'function' && onExpand(tableId, trData, trExpand); } return retValue; @@ -719,7 +829,9 @@ layui.define(['table'], function (exports) { tableView.find('.layui-table-box tbody tr[data-level!="0"]').addClass(HIDE); tableView.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconClose); - treeOptions.view.showIcon && tableView.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)').html(treeOptions.view.iconClose); + treeOptions.view.showIcon && tableView + .find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)') + .html(treeOptions.view.iconClose); } else { var tableDataFlat = treeTable.getData(id, true); // 展开所有 @@ -766,15 +878,20 @@ layui.define(['table'], function (exports) { tableView.find('tbody tr[data-level!="0"]').removeClass(HIDE); // 处理节点的图标 tableView.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconOpen); - treeOptions.view.showIcon && tableView.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)').html(treeOptions.view.iconOpen); + treeOptions.view.showIcon && tableView + .find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)') + .html(treeOptions.view.iconOpen); } else { - // 如果有未打开过的父节点,将内容全部生成 + // 如果有未打开过的父节点,将 tr 内容全部重新生成 that.updateStatus(null, function (d) { if (d[isParentKey]) { d[LAY_EXPAND] = true; d[LAY_HAS_EXPANDED] = true; } - }); // {LAY_EXPAND: true, LAY_HAS_EXPANDED: true}); + }); + if (options.initSort && options.initSort.type && (!options.url || options.autoSort)) { + return treeTable.sort(id); + } var trAll = table.getTrHtml(id, tableDataFlat); var trAllObj = { @@ -782,23 +899,17 @@ layui.define(['table'], function (exports) { trs_fixed: $(trAll.trs_fixed.join('')), trs_fixed_r: $(trAll.trs_fixed_r.join('')) } + var props; layui.each(tableDataFlat, function (dataIndex, dataItem) { var dataLevel = dataItem[LAY_DATA_INDEX].split('-').length - 1; - trAllObj.trs.eq(dataIndex).attr({ + props = { 'data-index': dataItem[LAY_DATA_INDEX], 'lay-data-index': dataItem[LAY_DATA_INDEX], 'data-level': dataLevel - }) - trAllObj.trs_fixed.eq(dataIndex).attr({ - 'data-index': dataItem[LAY_DATA_INDEX], - 'lay-data-index': dataItem[LAY_DATA_INDEX], - 'data-level': dataLevel - }) - trAllObj.trs_fixed_r.eq(dataIndex).attr({ - 'data-index': dataItem[LAY_DATA_INDEX], - 'lay-data-index': dataItem[LAY_DATA_INDEX], - 'data-level': dataLevel - }) + }; + trAllObj.trs.eq(dataIndex).attr(props) + trAllObj.trs_fixed.eq(dataIndex).attr(props) + trAllObj.trs_fixed_r.eq(dataIndex).attr(props) }) layui.each(['main', 'fixed-l', 'fixed-r'], function (i, item) { tableView.find('.layui-table-' + item + ' tbody').html(trAllObj[['trs', 'trs_fixed', 'trs_fixed_r'][i]]); @@ -813,7 +924,7 @@ layui.define(['table'], function (exports) { var that = this; var options = that.getOptions(); var tableViewElem = options.elem.next(); - tableViewElem.addClass(TABLE_TREE); + !tableViewElem.hasClass(TABLE_TREE) && tableViewElem.addClass(TABLE_TREE); var tableId = options.id; var treeOptions = options.tree || {}; var treeOptionsData = treeOptions.data || {}; @@ -836,7 +947,7 @@ layui.define(['table'], function (exports) { }) } - var dataExpand = {}; // 记录需要展开的数据 + var dataExpand = null; // 记录需要展开的数据 var nameKey = customName.name; var indent = treeOptionsView.indent || 14; layui.each(tableView.find('td[data-field="' + nameKey + '"]'), function (index, item) { @@ -846,21 +957,26 @@ layui.define(['table'], function (exports) { if (itemCell.hasClass('layui-table-tree-item')) { return; } - itemCell.addClass('layui-table-tree-item'); var trIndex = trElem.attr('lay-data-index'); if (!trIndex) { // 排除在统计行中的节点 return; } + trElem = tableViewElem.find('tr[lay-data-index="' + trIndex + '"]'); var trData = treeTableThat.getNodeDataByIndex(trIndex); + if (trData[LAY_EXPAND]) { // 需要展开 + dataExpand = dataExpand || {}; dataExpand[trIndex] = true; } + if (trData[LAY_CHECKBOX_HALF]) { + trElem.find('input[type="checkbox"][name="layTableCheckbox"]').prop('indeterminate', true); + } - var tableCellElem = item.find('div.layui-table-cell'); - var htmlTemp = tableCellElem.html(); - - var flexIconElem = item.find('div.layui-table-cell') + var htmlTemp = itemCell.html(); + itemCell = trElem.find('td[data-field="' + nameKey + '"]>div.layui-table-cell'); + itemCell.addClass('layui-table-tree-item'); + var flexIconElem = itemCell .html(['