🔥 fix(table): 修复表格列宽计算问题 (#2187)

* fix(table): 修复表格列宽计算问题

rebase

* update

* update

* update

* update
This commit is contained in:
morning-star 2024-09-23 22:47:01 +08:00 committed by GitHub
parent 045ac836ba
commit 8d14ef50e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -15,6 +15,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
var util = layui.util;
var hint = layui.hint();
var device = layui.device();
var isChrome = layui.device('chrome').chrome;
// api
var table = {
@ -483,9 +484,21 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
options.clientWidth = options.width || function(){ //获取容器宽度
//如果父元素宽度为0一般为隐藏元素则继续查找上层元素直到找到真实宽度为止
var getWidth = function(parent){
var width, isNone;
parent = parent || options.elem.parent()
width = parent.width();
var width;
var isNone;
parent = parent || options.elem.parent();
if(!window.getComputedStyle){
// IE 中的 `currentStyle` 获取未显式设置的宽高时会得到 'auto'jQuery 中有一些 hack 方法获取准确值
width = parent.width();
}else{
var size = that.getElementSize(parent[0]);
// IE BUG
// border-box: getComputedStyle 得到的 width/height 是按照 content-box 计算出来的
width = size.boxSizing === 'border-box' && !lay.ie
? size.width - size.paddingLeft - size.paddingRight - size.borderLeftWidth - size.borderRightWidth
: size.width
}
try {
isNone = parent.css('display') === 'none';
} catch(e){}
@ -902,16 +915,23 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
var autoWidth = 0; // 自动列分配的宽度
var countWidth = 0; // 所有列总宽度和
var cntrWidth = that.setInit('width');
var borderWidth = parseFloat(layui.getStyle(that.elem[0], 'border-right-width'));
var lastSpreadCol;
// 统计列个数
// 统计列个数和最后一个分配宽度的列
that.eachCols(function(i, item){
item.hide || colNums++;
if(!item.hide){
colNums++;
if(!(item.width || item.type !== 'normal')){
lastSpreadCol = item;
}
}
});
// 减去边框差和滚动条宽
cntrWidth = cntrWidth - function(){
return (options.skin === 'line' || options.skin === 'nob') ? 2 : colNums + 1;
}() - that.getScrollWidth(that.layMain[0]) - 1;
}() * borderWidth - that.getScrollWidth(that.layMain[0]);
// 计算自动分配的宽度
var getAutoWidth = function(back){
@ -932,7 +952,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
if(!back){
width = item2.width || 0;
if(/\d+%$/.test(width)){ // 列宽为百分比
width = Math.floor((parseFloat(width) / 100) * cntrWidth);
width = (parseFloat(width) / 100) * cntrWidth;
width < minWidth && (width = minWidth);
width > maxWidth && (width = maxWidth);
} else if(!width){ // 列宽未填写
@ -969,31 +989,34 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
// 记录自动列数
that.autoColNums = autoColNums = autoColNums > 0 ? autoColNums : 0;
// 设置列宽
var pixelsForLastCol = cntrWidth;
that.eachCols(function(i3, item3){
var minWidth = item3.minWidth || options.cellMinWidth;
var maxWidth = item3.maxWidth || options.cellMaxWidth;
if(item3.colGroup || item3.hide) return;
if(item3.colGroup || item3.hide || (lastSpreadCol && lastSpreadCol.key === item3.key)) return;
// 给未分配宽的列平均分配宽
if(item3.width === 0){
that.cssRules(item3.key, function(item){
item.style.width = Math.floor(function(){
var newWidth = Math.round(function(){
if(autoWidth < minWidth) return minWidth;
if(autoWidth > maxWidth) return maxWidth;
return autoWidth;
}()) + 'px';
}());
item.style.width = newWidth + 'px';
pixelsForLastCol = pixelsForLastCol - newWidth;
});
}
// 给设定百分比的列分配列宽
else if(/\d+%$/.test(item3.width)){
that.cssRules(item3.key, function(item){
var width = Math.floor((parseFloat(item3.width) / 100) * cntrWidth);
var width = Math.round((parseFloat(item3.width) / 100) * cntrWidth);
width < minWidth && (width = minWidth);
width > maxWidth && (width = maxWidth);
item.style.width = width + 'px';
pixelsForLastCol = pixelsForLastCol - width;
});
}
@ -1001,33 +1024,20 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
else {
that.cssRules(item3.key, function(item){
item.style.width = item3.width + 'px';
pixelsForLastCol = pixelsForLastCol - item3.width;
});
}
});
// 填补 Math.floor 造成的数差
var patchNums = that.layMain.width() - that.getScrollWidth(that.layMain[0])
- that.layMain.children('table').outerWidth();
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');
if(!field && th.prev()[0]){
return getEndTh(th.prev())
}
return th;
};
var th = getEndTh();
var key = th.data('key');
that.cssRules(key, function(item){
var width = item.style.width || th.outerWidth();
item.style.width = (parseFloat(width) + patchNums) + 'px';
// 最后一列获取剩余的空间,避免舍入导致的布局问题
if(lastSpreadCol){
that.cssRules(lastSpreadCol.key, function(item){
var minWidth = lastSpreadCol.minWidth || options.cellMinWidth;
var maxWidth = lastSpreadCol.maxWidth || options.cellMaxWidth;
var newWidth = Math.max(Math.min(pixelsForLastCol, maxWidth), minWidth);
item.style.width = newWidth + 'px';
// 二次校验,如果仍然出现横向滚动条(通常是 1px 的误差导致)
if(that.layMain.height() - that.layMain.prop('clientHeight') > 0){
if(isChrome && that.layMain.prop('offsetHeight') > that.layMain.prop('clientHeight')){
item.style.width = (parseFloat(item.style.width) - 1) + 'px';
}
});
@ -1043,7 +1053,6 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
} else {
that.layMain.find('table').width('auto');
}
};
// 重置表格尺寸/结构
@ -2789,6 +2798,33 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
that.layMain.scrollTop(scrollTop + (delta > 0 ? -step : step));
});
}
/**
* 获取元素的大小
* @param {HTMLElement} elem - HTML 元素
*/
Class.prototype.getElementSize = function(elem){
if(!window.getComputedStyle) return;
var style = window.getComputedStyle(elem, null);
return {
height: parseFloat(style.height || '0'),
width: parseFloat(style.width || '0'),
borderTopWidth: parseFloat(style.borderTopWidth || '0'),
borderRightWidth: parseFloat(style.borderRightWidth || '0'),
borderBottomWidth: parseFloat(style.borderBottomWidth || '0'),
borderLeftWidth: parseFloat(style.borderLeftWidth || '0'),
paddingTop: parseFloat(style.paddingTop || '0'),
paddingRight: parseFloat(style.paddingRight || '0'),
paddingBottom: parseFloat(style.paddingBottom || '0'),
paddingLeft: parseFloat(style.paddingLeft || '0'),
marginTop: parseFloat(style.marginTop || '0'),
marginRight: parseFloat(style.marginRight || '0'),
marginBottom: parseFloat(style.marginBottom || '0'),
marginLeft: parseFloat(style.marginLeft || '0'),
boxSizing: style.boxSizing
}
};
// 全局事件