diff --git a/src/modules/table.js b/src/modules/table.js index e06ca2e2..eaf43c4e 100644 --- a/src/modules/table.js +++ b/src/modules/table.js @@ -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 + } }; // 全局事件