/** * 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, set: function (options) { var that = this; that.config = $.extend({}, that.config, options); return that; }, resize: table.resize }; // 操作当前实例 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 LAY_CHECKBOX_HALF = 'LAY_CHECKBOX_HALF'; var LAY_EXPAND = 'LAY_EXPAND'; var LAY_HAS_EXPANDED = 'LAY_HAS_EXPANDED'; // 构造器 var Class = function (options) { var that = this; that.index = ++treeTable.index; that.config = $.extend(true, {}, that.config, treeTable.config, options); // 处理一些属性 that.init(); 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; // 先初始一个空的表格以便拿到对应的表格实例信息 var tableIns = table.render($.extend({}, options, { data: [], url: '', done: null })) var id = tableIns.config.id; thisTreeTable.that[id] = that; // 记录当前实例对象 that.tableIns = tableIns; var treeOptions = options.tree; var customName = treeOptions.customName; var isParentKey = customName.isParent; var childrenKey = customName.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; // 处理 isSimpleData if (treeOptions.data.isSimpleData && !treeOptions.async.enable) { // 异步加载和 isSimpleData 不应该一起使用 retData[dataName] = that.flatToTree(retData[dataName]); } that.initData(retData[dataName]); return retData; } } else { options.data = options.data || []; // 处理 isSimpleData if (treeOptions.data.isSimpleData) { 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 // 去除已经打开过的状态 }); // 更新cache中的内容 将子节点也存到cache中 updateCache(id, childrenKey); // 更新全选框的状态 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); if (layui.type(done) === 'function') { return done.apply(doneThat, args); } } } // 初始默认配置 Class.prototype.config = { tree: { customName: { children: "children", // 节点数据中保存子节点数据的属性名称 isParent: "isParent", // 节点数据保存节点是否为父节点的属性名称 name: "name", // 节点数据保存节点名称的属性名称 id: "id", // 唯一标识的属性名称 pid: "parentId", rootId: null }, view: { indent: 14, // 层级缩进量 flexIconClose: '', // 关闭时候的折叠图标 flexIconOpen: '', // 打开时候的折叠图标 showIcon: true, // 是否显示图标(节点类型图标) icon: '', // 节点图标,如果设置了这个属性或者数据中有这个字段信息,不管打开还是关闭都以这个图标的值为准 iconClose: '', // 打开时候的图标 iconOpen: '', // 关闭时候的图标 iconLeaf: '', // 叶子节点的图标 showFlexIconIfNotParent: false, // 当节点不是父节点的时候是否显示折叠图标 dblClickExpand: true, // 双击节点时,是否自动展开父节点的标识 }, data: { isSimpleData: false // 是否简单数据模式 }, 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 table.getOptions(that.tableIns.config.id); // 获取表格的实时配置信息 } else { return that.config; } }; function flatToTree(flatArr, idKey, pIdKey, childrenKey, rootPId) { 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); } }) // 返回顶层节点 return Object.values(nodes).filter(function (item) { return rootPId ? item[pIdKey] === rootPId : !item[pIdKey]; }) } Class.prototype.flatToTree = function (tableData) { var that = this; var options = that.getOptions(); var treeOptions = options.tree; var customName = treeOptions.customName; var tableId = options.id; tableData = tableData || table.cache[tableId]; return flatToTree(tableData, customName.id, customName.pid, customName.children, customName.rootId) } Class.prototype.treeToFlat = function (tableData, parentId, parentIndex) { var that = this; var options = that.getOptions(); var treeOptions = options.tree; var customName = treeOptions.customName; var childrenKey = customName.children; var pIdKey = customName.pid; 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[customName.id], 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 dataCache = table.cache[tableId][index]; if (newValue !== 'delete' && dataCache) { return clone ? $.extend({}, dataCache) : dataCache; } var tableData = that.getTableData(); index += ''; var indexArr = index.split('-'); var dataRet = tableData; var tableCache = (options.url || indexArr.length > 1) ? null : table.cache[tableId]; // 只有在删除根节点的时候才需要处理 for (var i = 0, childrenKey = treeOptions.customName.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); 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 { // 更新值 $.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); if(!that) return; 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 || that.getTableData(); var customName = treeOptions.customName; var isParentKey = customName.isParent; var childrenKey = customName.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 = parentIndex || ''; var dataIndex = item1[LAY_DATA_INDEX] = (parentIndex ? parentIndex + '-' : '') + i1; that.initData(item1[childrenKey] || [], dataIndex); }); parentIndex || updateCache(tableId, childrenKey); 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 options = table.getOptions(tableId); var treeOptions = options.tree || {}; var customName = treeOptions.customName || {}; var isParentKey = customName.isParent; var trIndex = trElem.attr('lay-data-index'); // 可能出现多层 var treeTableThat = getThisTable(tableId); var tableData = treeTableThat.getTableData(); var trData = treeTableThat.getNodeDataByIndex(trIndex); var dataLevel = trElem.data('level'); var dataLevelNew = (dataLevel || 0) + 1; // 后续调优:对已经展开的节点进行展开和已经关闭的节点进行关闭应该做优化减少不必要的代码执行 todo var isToggle = layui.type(expandFlag) !== 'boolean'; var trExpand = isToggle ? !trData[LAY_EXPAND] : expandFlag; var retValue = trData[isParentKey] ? trExpand : null; 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) { return retValue; } } } 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(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(trExpand ? treeOptions.view.iconOpen : treeOptions.view.iconClose); } var childNodes = trData[customName.children] || []; // 测试用后续需要改成子节点的字段名称 // 处理子节点展示与否 if (trExpand) { // 展开 if (trExpanded) { // 已经展开过 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'); layui.each(childNodes, function (i1, item1) { 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]) { // 级联展开 expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, true); } }) } 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 = {}; // 参数 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) { trData['LAY_ASYNC_STATUS'] = 'error'; // 异常处理 todo 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); } } , error: function (e, msg) { trData['LAY_ASYNC_STATUS'] = 'error'; // 异常处理 todo typeof options.error === 'function' && options.error(e, msg); } }); return retValue; } trData[LAY_EXPAND] = trExpand; trExpanded = trData[LAY_HAS_EXPANDED] = true; if (childNodes.length) { // 判断是否需要排序 if (options.initSort && !options.url) { var initSort = options.initSort; if (initSort.type) { childNodes = trData[customName.children] = layui.sort(childNodes, initSort.field, initSort.type === 'desc'); } else { // 恢复默认 childNodes = trData[customName.children] = layui.sort(childNodes, table.config.indexName); } } treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX]); // 将数据通过模板得出节点的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], '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[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) { treeTableThat.renderTreeTable(item, dataLevelNew); }) if (sonSign && !isToggle) { // 非状态切换的情况下 // 级联展开/关闭子节点 layui.each(childNodes, function (i1, item1) { expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + item1.LAY_DATA_INDEX + '"]').first()}, expandFlag, sonSign, focus, callbackFlag); }) } } } } else { trData[LAY_EXPAND] = trExpand; // 折叠 if (sonSign && !isToggle) { // 非状态切换的情况下 layui.each(childNodes, function (i1, item1) { 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[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' }).join(',')).addClass('layui-hide'); } else { var childNodesFlat = treeTableThat.treeToFlat(childNodes, trData[customName.id], trIndex); tableViewElem.find(childNodesFlat.map(function (value, index, array) { return 'tr[lay-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, opts) { var that = getThisTable(id); if(!that) return; opts = opts || {}; var index = opts.index; var expandFlag = opts.expandFlag; var sonSign = opts.inherit; var callbackFlag = opts.callbackFlag; var options = that.getOptions(); var tableViewElem = options.elem.next(); return expandNode({trElem: tableViewElem.find('tr[lay-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') } var that = getThisTable(id); if(!that) return; var options = that.getOptions(); var treeOptions = options.tree; var tableView = options.elem.next(); if (!expandFlag) { // 关闭所有 // 将所有已经打开的节点的状态设置为关闭, that.updateStatus(null, {LAY_EXPAND: false}); // 只处理当前页,如果需要处理全部表格,需要用treeTable.updateStatus // 隐藏所有非顶层的节点 tableView.find('tbody tr[data-level!="0"]').addClass('layui-hide'); // 处理顶层节点的图标 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 { return hint.error('暂不支持展开全部'); // 展开所有 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 { // 如果有未打开过的父节点,将内容全部生成 that.updateStatus(null, {LAY_EXPAND: true, LAY_HAS_EXPANDED: true}); var trsAll = table.getTrHtml(id, tableDataFlat); } } // 如果是异步加载子节点模式 如何处理 // 如果有部分节点未打开过,也需要重新 } } 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 customName = treeOptions.customName || {}; var isParentKey = customName.isParent; var tableFilterId = tableViewElem.attr('lay-filter'); var treeTableThat = that; // var tableData = treeTableThat.getTableData(); level = level || 0; if (!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('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]); }) } var dataExpand = {}; // 记录需要展开的数据 var nameKey = customName.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('lay-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(['