/**
*
* @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('
')
} 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('
')
for (i = 0; i < children.length; i++) {
tables.push('- ' + (typeof children[i].title === 'function' ? children[i].title(data) : children[i].title) + '
');
}
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);
});