/** * * @name: 子表格扩展 * @author: yelog * @version: v1.4.4 */ layui.define(['table', 'element', 'form', 'laytpl'], function (exports) { var $ = layui.jquery, table = layui.table, laytpl = layui.laytpl, tableChildren = {}, ELEM_HOVER = 'soul-table-hover'; // 封装方法 var mod = { /** * 渲染入口 * @param myTable */ render: function (myTable) { var _this = this, $table = $(myTable.elem), $tableBox = $table.next().children('.layui-table-box'), tableId = myTable.id, $tableHead = $tableBox.children('.layui-table-header').children('table'), $fixedBody = $tableBox.children('.layui-table-fixed').children('.layui-table-body').children('table'), $noFixedBody = $tableBox.children('.layui-table-body').children('table'), $tableBody = $.merge($tableBox.children('.layui-table-body').children('table'), $fixedBody), columns = _this.getCompleteCols(myTable.cols), childIndex = [], soulSort = typeof myTable.soulSort === 'undefined' || myTable.soulSort, i; // 修复hover样式 _this.fixHoverStyle(myTable) // 获取子表配置信息 for (i = 0; i < columns.length; i++) { if (columns[i].children && columns[i].children.length > 0) { childIndex.push(i); } } if (typeof $table.attr('lay-filter') === 'undefined') { $table.attr('lay-filter', tableId); } // 绑定一下主表事件 if ($table.parents('.childTr').length === 0) { if (typeof myTable.rowEvent === 'function') { table.on('row(' + $table.attr('lay-filter') + ')', function (obj) { var index = $(this).data('index'); obj.tr = $tableBody.children('tbody').children('tr[data-index="' + index + '"]'); myTable.rowEvent(obj); }) } if (typeof myTable.rowDoubleEvent === 'function') { table.on('rowDouble(' + $table.attr('lay-filter') + ')', function (obj) { var index = $(this).data('index'); obj.tr = $tableBody.children('tbody').children('tr[data-index="' + index + '"]'); myTable.rowDoubleEvent(obj); }) } } if (childIndex.length > 0) { for (i = 0; i < childIndex.length; i++) { (function f() { var child = columns[childIndex[i]] , curIndex = childIndex[i] , icon = child.icon || ['layui-icon layui-icon-right', 'layui-icon layui-icon-down']; if (soulSort && !(myTable.url && myTable.page)) { // 前台排序 table.on('sort(' + $table.attr('lay-filter') + ')', function () { _this.render(myTable) }); } if (child.isChild && typeof child.isChild === 'function') { $tableBody.find('tr').find('td[data-key$="' + child.key + '"]>div').each(function (index) { if (child.isChild(layui.table.cache[tableId][index])) { if (child.field) { $(this).prepend(''); } else { $(this).html(''); } } }) } else { if (child.field) { $tableBody.find('tr').find('td[data-key$="' + child.key + '"]>div').prepend(''); } else { $tableBody.find('tr').find('td[data-key$="' + child.key + '"]>div').html(''); } } $tableBody.children('tbody').children('tr').each(function () { $(this).children('td:eq(' + curIndex + ')').find('.childTable').on('click', function (e) { layui.stope(e) var rowIndex = $(this).parents('tr:eq(0)').data('index'), key = $(this).parents('td:eq(0)').data('key'), $this = $noFixedBody.children('tbody').children('tr[data-index=' + rowIndex + ']').children('td[data-key="' + key + '"]').find('.childTable:eq(0)'), $fixedThis = $fixedBody.find('tr[data-index=' + rowIndex + ']').children('td[data-key="' + key + '"]').find('.childTable:eq(0)'), data = table.cache[myTable.id][rowIndex], children = child.children; if (typeof child.children === 'function') { children = child.children(data) } if (child.show === 2) { // 弹窗模式 layer.open($.extend({ type: 1, title: '子表', maxmin: true, content: _this.getTables(this, data, child, myTable, children), area: '1000px', offset: '100px' }, child.layerOption || {})); _this.renderTable(this, data, child, myTable, children, icon); } else { // 展开模式 // 开启手风琴模式 if (!$this.hasClass(icon[1]) && child.collapse) { $tableBody.children('tbody').children('tr').children('td').find('.childTable').each(function () { if ($(this).hasClass(icon[1])) { _this.destroyChildren($(this).parents('tr:eq(0)').data('index'), myTable, icon) } }) } // 多个入口时,关闭其他入口 if (!$this.hasClass(icon[1])) { $this.parents('tr:eq(0)').children('td').find('.childTable').each(function () { if ($(this).hasClass(icon[1])) { $(this).removeClass(icon[1]).addClass(icon[0]) _this.destroyChildren($(this).parents('tr:eq(0)').data('index'), myTable, icon) } }) } if ($this.hasClass(icon[1])) { $this.removeClass(icon[1]).addClass(icon[0]) $fixedThis.removeClass(icon[1]).addClass(icon[0]) } else { $this.removeClass(icon[0]).addClass(icon[1]) $fixedThis.removeClass(icon[0]).addClass(icon[1]) } var rowspanIndex = $this.parents('td:eq(0)').attr("rowspan"); if ($this.hasClass(icon[1])) { var newTr = []; newTr.push(''); newTr.push(_this.getTables(this, data, child, myTable, children)); newTr.push(''); if (rowspanIndex) { var index = parseInt($this.parents('tr:eq(0)').data("index")) + parseInt(rowspanIndex) - 1; $this.parents('table:eq(0)').children().children("[data-index='" + index + "']").after(newTr.join('')); } else { $this.parents('tr:eq(0)').after(newTr.join('')); } _this.renderTable(this, data, child, myTable, children, icon); if ($fixedBody.length > 0) { var $tr = $this.parents('tr:eq(0)').next(), height = $tr.children('td').height(), $patchDiv = '
'; $tr.children('td').children('.layui-tab-card').css({ position: 'absolute', top: 0, width: '100%', background: 'white', 'z-index': 200 }) $tr.children('td').append($patchDiv); $fixedBody.find('tr[data-index="' + rowIndex + '"]').each(function () { $(this).after('' + $patchDiv + '') }) table.resize(tableId) } if (child.show === 3) { $this.parents('tr:eq(0)').next().find('.layui-table-view').css({ margin: 0, 'border-width': 0 }); $this.parents('tr:eq(0)').next().find('.layui-table-header').css('display', 'none'); } // 阻止事件冒泡 $this.parents('tr:eq(0)').next().children('td').children('.layui-tab').children('.layui-tab-content').on('click', function (e) { e.stopPropagation() }).off('dblclick').on('dblclick', function (e) { e.stopPropagation() }).on('mouseenter', 'td', function (e) { e.stopPropagation() }) } else { _this.destroyChildren(rowIndex, myTable, icon); table.resize(tableId) } } }) }) if (child.spread && child.show !== 2) { $tableBody.children('tbody').children('tr').children('td').find('.childTable').trigger('click'); } })() } } }, /** * 生成子表内容 * @param _this * @param data * @param child * @param myTable * @param children 子表配置 * @returns {string} */ getTables: function (_this, data, child, myTable, children) { var tables = [], $table = $(myTable.elem), tableId = myTable.id, rowTableId = tableId + $(_this).parents('tr:eq(0)').data('index'), $tableMain = $table.next().children('.layui-table-box').children('.layui-table-body'), $tableBody = $tableMain.children('table'), scrollWidth = 0, i; tables.push('
') } else if (child.show === 3) { //不限制宽度 tables.push('">') } else { if (child.childWidth === 'full') { //不限制宽度 tables.push('">') } else { if ($tableMain.prop('scrollHeight') + (children.length > 0 ? children[0].height : 0) > $tableMain.height()) { scrollWidth = this.getScrollWidth(); } tables.push('max-width: ' + ($tableMain.width() - 1 - scrollWidth) + 'px">') } } if (child.show !== 3 && (typeof child.childTitle === 'undefined' || child.childTitle)) { tables.push('') } if (child.show === 3) { tables.push('
'); } else { tables.push('
'); } for (i = 0; i < children.length; i++) { var childTableId = rowTableId + i; tables.push('
'); } tables.push('
'); return tables.join('') }, /** * 渲染子表 * @param _this * @param data 父表当前行数据 * @param child 子表列 * @param myTable 父表配置 * @param children 子表配置 */ renderTable: function (_this, data, child, myTable, children, icon) { var tables = [] , _that = this , tableId = myTable.id , rowTableId = tableId + $(_this).parents('tr:eq(0)').data('index'); if (child.lazy) { tables.push(renderChildTable(_that, _this, data, child, myTable, 0, children, icon)); } else { for (var i = 0; i < children.length; i++) { tables.push(renderChildTable(_that, _this, data, child, myTable, i, children, icon)); } } tableChildren[rowTableId] = tables; layui.element.on('tab(table-child-' + rowTableId + ')', function (tabData) { if (child.lazy) { var isRender = false; // 是否已经渲染 for (i = 0; i < tableChildren[rowTableId].length; i++) { if (tableChildren[rowTableId][i].config.id === (rowTableId + tabData.index)) { isRender = true; break; } } if (!isRender) { tableChildren[rowTableId].push(renderChildTable(_that, _this, data, child, myTable, tabData.index, children)) } } var rowIndex = $(_this).parents('tr:eq(0)').data('index'), height = $(tabData.elem).height(); $(_this).parents('.layui-table-box:eq(0)').children('.layui-table-body').children('table').children('tbody').children('tr[data-index=' + rowIndex + ']').next().children().children('.soul-table-child-patch').css('height', height) $(_this).parents('.layui-table-box:eq(0)').children('.layui-table-fixed').children('.layui-table-body').children('table').children('tbody').children('tr[data-index=' + rowIndex + ']').next().children().children('.soul-table-child-patch').css('height', height) table.resize(tableId) }); function renderChildTable(_that, _this, data, child, myTable, i, children, icon) { var param = _that.deepClone(children[i]), thisTableChild, tableId = myTable.id, rowIndex = $(_this).parents('tr:eq(0)').data('index'), childTableId = tableId + rowIndex + i, $table = $(myTable.elem), $tableBox = $table.next().children('.layui-table-box'), $tableBody = $.merge($tableBox.children('.layui-table-body').children('table'), $tableBox.children('.layui-table-fixed').children('.layui-table-body').children('table')), tr = $tableBody.children('tbody').children('tr[data-index="' + rowIndex + '"]'), row = table.cache[tableId][rowIndex], // 父表当前行对象 pobj = { data: row, tr: tr, del: function () { table.cache[tableId][rowIndex] = []; _that.destroyChildren(rowIndex, myTable, icon) tr.remove(); table.resize(tableId); }, update: function (fields) { fields = fields || {}; layui.each(fields, function (key, value) { if (key in row) { var templet, td = tr.children('td[data-field="' + key + '"]'); row[key] = value; table.eachCols(tableId, function (i, item2) { if (item2.field == key && item2.templet) { templet = item2.templet; } }); td.children('.layui-table-cell').html(function () { return templet ? function () { return typeof templet === 'function' ? templet(row) : laytpl($(templet).html() || value).render(row) }() : value; }()); td.data('content', value); } }); }, close: function () { _that.destroyChildren(rowIndex, myTable, icon) table.resize(tableId); } }; param.id = childTableId; param.elem = '#' + childTableId; typeof param.where === 'function' && (param.where = param.where(data)); typeof param.data === 'function' && (param.data = param.data(data)); typeof param.url === 'function' && (param.url = param.url(data)); thisTableChild = table.render(param); if (!child.lazy && i !== 0) { $('#' + childTableId).parents('.layui-tab-item:eq(0)').removeClass('layui-show'); //解决隐藏时计算表格高度有问题 } // 绑定 checkbox 事件 if (typeof param.checkboxEvent === 'function') { table.on('checkbox(' + childTableId + ')', function (obj) { param.checkboxEvent(obj, pobj) }) } // 绑定 edit 事件 if (typeof param.editEvent === 'function') { table.on('edit(' + childTableId + ')', function (obj) { obj.oldValue = $(this).prev().text(); param.editEvent(obj, pobj) }) } // 绑定 tool 事件 if (typeof param.toolEvent === 'function') { table.on('tool(' + childTableId + ')', function (obj) { param.toolEvent(obj, pobj) }) } // 绑定 toolbar 事件 if (typeof param.toolbarEvent === 'function') { table.on('toolbar(' + childTableId + ')', function (obj) { param.toolbarEvent(obj, pobj) }) } // 绑定单击行事件 if (typeof param.rowEvent === 'function') { table.on('row(' + childTableId + ')', function (obj) { param.rowEvent(obj, pobj) }) } // 绑定双击行事件 if (typeof param.rowDoubleEvent === 'function') { table.on('rowDouble(' + childTableId + ')', function (obj) { param.rowDoubleEvent(obj, pobj) }) } return thisTableChild; } }, destroyChildren: function (rowIndex, myTable, icon) { var tableId = myTable.id, $table = $(myTable.elem), $tableBox = $table.next().children('.layui-table-box'), $fixedBody = $tableBox.children('.layui-table-fixed').children('.layui-table-body').children('table'), $tableBody = $.merge($tableBox.children('.layui-table-body').children('table'), $fixedBody), $tr = $tableBody.children('tbody').children('tr[data-index="' + rowIndex + '"]'); $tr.find('.childTable').removeClass(icon[1]).addClass(icon[0]); // 暂时不处理 rowspan 情况 // var rowspanIndex = $this.parents('td:eq(0)').attr("rowspan"); // if(rowspanIndex){ // var index=$this.parents('tr:eq(0)').index()+parseInt(rowspanIndex); // $this.parents('table:eq(0)').children().children('tr:eq('+index+')').remove() // }else{ // $this.parents('tr:eq(0)').next().remove(); // } $tr.next().remove() var tables = tableChildren[tableId + rowIndex]; if (layui.tableFilter) { //如果使用了筛选功能,怎同时清理筛选渲染的数据 layui.tableFilter.destroy(tables); } delete tableChildren[tableId + rowIndex] }, cloneJSON: function (obj) { var JSON_SERIALIZE_FIX = { PREFIX: "[[JSON_FUN_PREFIX_", SUFFIX: "_JSON_FUN_SUFFIX]]" }; var sobj = JSON.stringify(obj, function (key, value) { if (typeof value === 'function') { return JSON_SERIALIZE_FIX.PREFIX + value.toString() + JSON_SERIALIZE_FIX.SUFFIX; } return value; }); return JSON.parse(sobj, function (key, value) { if (typeof value === 'string' && value.indexOf(JSON_SERIALIZE_FIX.SUFFIX) > 0 && value.indexOf(JSON_SERIALIZE_FIX.PREFIX) === 0) { return eval("(" + value.replace(JSON_SERIALIZE_FIX.PREFIX, "").replace(JSON_SERIALIZE_FIX.SUFFIX, "") + ")"); } return value; }) || {}; }, fixHoverStyle: function (myTable) { var $table = $(myTable.elem) , $tableBody = $table.next().children('.layui-table-box').children('.layui-table-body').children('table') , $tableFixed = $table.next().children('.layui-table-box').children('.layui-table-fixed').children('.layui-table-body').children('table') , style = $table.next().find('style')[0], sheet = style.sheet || style.styleSheet || {}; // 屏蔽掉layui原生 hover 样式 this.addCSSRule(sheet, '.layui-table-hover', 'background-color: inherit'); this.addCSSRule(sheet, '.layui-table-hover.soul-table-hover', 'background-color: #F2F2F2'); $.merge($tableFixed.children('tbody').children('tr'), $tableBody.children('tbody').children('tr')) .on('mouseenter', function () { var othis = $(this) , index = $(this).data('index'); if (othis.data('off')) return; $tableFixed.children('tbody').children('tr[data-index=' + index + ']').addClass(ELEM_HOVER); $tableBody.children('tbody').children('tr[data-index=' + index + ']').addClass(ELEM_HOVER); }).on('mouseleave', function () { var othis = $(this) , index = $(this).data('index'); if (othis.data('off')) return; $tableFixed.children('tbody').children('tr[data-index=' + index + ']').removeClass(ELEM_HOVER); $tableBody.children('tbody').children('tr[data-index=' + index + ']').removeClass(ELEM_HOVER); }) }, addCSSRule: function (sheet, selector, rules, index) { if ('insertRule' in sheet) { sheet.insertRule(selector + '{' + rules + '}', index) } else if ('addRule' in sheet) { sheet.addRule(selector, rules, index) } }, // 深度克隆-不丢失方法 deepClone: function (obj) { var newObj = Array.isArray(obj) ? [] : {} if (obj && typeof obj === "object") { for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = (obj && typeof obj[key] === 'object') ? this.deepClone(obj[key]) : obj[key]; } } } return newObj }, getCompleteCols: function (origin) { var cols = this.deepClone(origin); var i, j, k, cloneCol; for (i = 0; i < cols.length; i++) { for (j = 0; j < cols[i].length; j++) { if (!cols[i][j].exportHandled) { if (cols[i][j].rowspan > 1) { cloneCol = this.deepClone(cols[i][j]) cloneCol.exportHandled = true; k = i + 1; while (k < cols.length) { cols[k].splice(j, 0, cloneCol) k++ } } if (cols[i][j].colspan > 1) { cloneCol = this.deepClone(cols[i][j]) cloneCol.exportHandled = true; for (k = 1; k < cols[i][j].colspan; k++) { cols[i].splice(j, 0, cloneCol) } j = j + cols[i][j].colspan - 1 } } } } return cols[cols.length - 1]; }, getScrollWidth: function (elem) { var width = 0; if (elem) { width = elem.offsetWidth - elem.clientWidth; } else { elem = document.createElement('div'); elem.style.width = '100px'; elem.style.height = '100px'; elem.style.overflowY = 'scroll'; document.body.appendChild(elem); width = elem.offsetWidth - elem.clientWidth; document.body.removeChild(elem); } return width; } }; // 输出 exports('tableChild', mod); });