mirror of https://github.com/layui/layui
fix(table): 修复自动行高时固定列高度异常 (#2825)
* fix(select): select 面板大小变化时重新定位 * update * fix(table): 修复自动行高时固定列高度异常 * feat(table): 新增 syncFixedRowHeight 选项 * update * update * update * update * update * fix: 重复 render 时停止 onserveResize * update * docs: 更新 table 文档 * fix: 修复一些边缘情况 * fix: 修复边缘情况main
parent
182c0bcedd
commit
1ec6c91da6
|
@ -254,6 +254,17 @@ height: function(){
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>string</td>
|
<td>string</td>
|
||||||
|
<td>-</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>syncFixedRowHeight <sup>2.12+ 实验性</sup></td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
是否强制计算表格主区域的行高度并同步到固定列区域。开启后会对表格性能有一定的影响,仅适用于行高度自适应的场景。
|
||||||
|
该功能使用 [ResizeObserver](https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver) 实现,如果你的浏览器不支持 `ResizeObserver`,可以尝试添加 [polyfill](https://github.com/que-etc/resize-observer-polyfill) 来解决兼容性问题。
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>boolean</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -151,9 +151,12 @@ layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(expo
|
||||||
var ELEM_TOOL_PANEL = 'layui-table-tool-panel';
|
var ELEM_TOOL_PANEL = 'layui-table-tool-panel';
|
||||||
var ELEM_EXPAND = 'layui-table-expanded';
|
var ELEM_EXPAND = 'layui-table-expanded';
|
||||||
var DISABLED_TRANSITION = 'layui-table-disabled-transition';
|
var DISABLED_TRANSITION = 'layui-table-disabled-transition';
|
||||||
|
var FIXED_HEIGHT_PATCH = 'layui-table-fixed-height-patch';
|
||||||
|
|
||||||
var DATA_MOVE_NAME = 'LAY_TABLE_MOVE_DICT';
|
var DATA_MOVE_NAME = 'LAY_TABLE_MOVE_DICT';
|
||||||
|
|
||||||
|
var resizeObserver = lay._createResizeObserver(MOD_NAME);
|
||||||
|
|
||||||
// thead 区域模板
|
// thead 区域模板
|
||||||
var TPL_HEADER = function(options){
|
var TPL_HEADER = function(options){
|
||||||
var rowCols = '{{#var colspan = layui.type(item2.colspan2) === \'number\' ? item2.colspan2 : item2.colspan; if(colspan){}} colspan="{{=colspan}}"{{#} if(item2.rowspan){}} rowspan="{{=item2.rowspan}}"{{#}}}';
|
var rowCols = '{{#var colspan = layui.type(item2.colspan2) === \'number\' ? item2.colspan2 : item2.colspan; if(colspan){}} colspan="{{=colspan}}"{{#} if(item2.rowspan){}} rowspan="{{=item2.rowspan}}"{{#}}}';
|
||||||
|
@ -288,6 +291,7 @@ layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(expo
|
||||||
var that = this;
|
var that = this;
|
||||||
that.index = ++table.index;
|
that.index = ++table.index;
|
||||||
that.config = $.extend({}, that.config, table.config, options);
|
that.config = $.extend({}, that.config, table.config, options);
|
||||||
|
that.unobserveResize = $.noop;
|
||||||
that.render();
|
that.render();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -318,6 +322,11 @@ layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(expo
|
||||||
options.elem.attr('id') || that.index
|
options.elem.attr('id') || that.index
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 重复 render 时清理旧实例
|
||||||
|
if(thisTable.that[id] && thisTable.that[id] !== that){
|
||||||
|
thisTable.that[id].dispose();
|
||||||
|
}
|
||||||
|
|
||||||
thisTable.that[id] = that; // 记录当前实例对象
|
thisTable.that[id] = that; // 记录当前实例对象
|
||||||
thisTable.config[id] = options; // 记录当前实例配置项
|
thisTable.config[id] = options; // 记录当前实例配置项
|
||||||
|
|
||||||
|
@ -460,6 +469,7 @@ layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(expo
|
||||||
|
|
||||||
that.pullData(that.page); // 请求数据
|
that.pullData(that.page); // 请求数据
|
||||||
that.events(); // 事件
|
that.events(); // 事件
|
||||||
|
that.observeResize(); // 观察尺寸变化
|
||||||
};
|
};
|
||||||
|
|
||||||
// 根据列类型,定制化参数
|
// 根据列类型,定制化参数
|
||||||
|
@ -622,6 +632,7 @@ layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(expo
|
||||||
|
|
||||||
// 自定义 css 属性
|
// 自定义 css 属性
|
||||||
if (options.css) text.push(options.css);
|
if (options.css) text.push(options.css);
|
||||||
|
text.push('.' + FIXED_HEIGHT_PATCH + '{height:auto;}');
|
||||||
|
|
||||||
// 生成 style
|
// 生成 style
|
||||||
lay.style({
|
lay.style({
|
||||||
|
@ -1521,6 +1532,11 @@ layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(expo
|
||||||
}, 50);
|
}, 50);
|
||||||
that.haveInit = true;
|
that.haveInit = true;
|
||||||
|
|
||||||
|
// reloadData 或 renderData 时,tbody 高度可能不变,需要主动同步
|
||||||
|
if(that.needSyncFixedRowHeight){
|
||||||
|
that.calcFixedRowHeight();
|
||||||
|
}
|
||||||
|
|
||||||
layer.close(that.tipsIndex);
|
layer.close(that.tipsIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2530,12 +2546,20 @@ layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(expo
|
||||||
var othis = $(this);
|
var othis = $(this);
|
||||||
var index = othis.index();
|
var index = othis.index();
|
||||||
if(othis.data('off')) return; // 不触发事件
|
if(othis.data('off')) return; // 不触发事件
|
||||||
that.layBody.find('tr:eq('+ index +')').addClass(ELEM_HOVER)
|
var trsElem = that.layBody.find('tr:eq('+ index +')');
|
||||||
|
trsElem.addClass(ELEM_HOVER);
|
||||||
|
if(that.needSyncFixedRowHeight){
|
||||||
|
that.fixedRowHeightPatchOnHover(this, trsElem, true);
|
||||||
|
}
|
||||||
}).on('mouseleave', 'tr', function(){ // 鼠标移出行
|
}).on('mouseleave', 'tr', function(){ // 鼠标移出行
|
||||||
var othis = $(this);
|
var othis = $(this);
|
||||||
var index = othis.index();
|
var index = othis.index();
|
||||||
if(othis.data('off')) return; // 不触发事件
|
if(othis.data('off')) return; // 不触发事件
|
||||||
that.layBody.find('tr:eq('+ index +')').removeClass(ELEM_HOVER)
|
var trsElem = that.layBody.find('tr:eq('+ index +')');
|
||||||
|
trsElem.removeClass(ELEM_HOVER);
|
||||||
|
if(that.needSyncFixedRowHeight){
|
||||||
|
that.fixedRowHeightPatchOnHover(this, trsElem, false);
|
||||||
|
}
|
||||||
}).on('click', 'tr', function(e){ // 单击行
|
}).on('click', 'tr', function(e){ // 单击行
|
||||||
setRowEvent.call(this, 'row', e);
|
setRowEvent.call(this, 'row', e);
|
||||||
}).on('dblclick', 'tr', function(e){ // 双击行
|
}).on('dblclick', 'tr', function(e){ // 双击行
|
||||||
|
@ -2922,6 +2946,119 @@ layui.define(['lay', 'i18n', 'laytpl', 'laypage', 'form', 'util'], function(expo
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Class.prototype.dispose = function(){
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.unobserveResize();
|
||||||
|
for (const propName in that) {
|
||||||
|
if(lay.hasOwn(that, propName) && propName !== 'config'){
|
||||||
|
that[propName] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Class.prototype.calcFixedRowHeight = function(){
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
var tableElem = that.layMain.children('table');
|
||||||
|
var leftTrs = that.layFixLeft.find('>.layui-table-body>table>tbody>tr');
|
||||||
|
var rightTrs = that.layFixRight.find('>.layui-table-body>table>tbody>tr');
|
||||||
|
var mainTrs = tableElem.find('>tbody>tr');
|
||||||
|
|
||||||
|
// 批量获取主表格行高,设置高度以优化性能
|
||||||
|
var heights = [];
|
||||||
|
mainTrs.each(function() {
|
||||||
|
heights.push(that.getElementSize(this).height);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (leftTrs.length) {
|
||||||
|
leftTrs.each(function(i) {
|
||||||
|
if (heights[i]) {
|
||||||
|
this.style.height = heights[i] + 'px';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightTrs.length) {
|
||||||
|
rightTrs.each(function(i) {
|
||||||
|
if (heights[i]) {
|
||||||
|
this.style.height = heights[i] + 'px';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 鼠标悬停于某一列纵向移动时,若单元格会出现横向滚动条,此时 tbody 高度不变,需要修复行高
|
||||||
|
Class.prototype.fixedRowHeightPatchOnHover = function (targetEl, trsElem, isEnter) {
|
||||||
|
var that = this;
|
||||||
|
var style = that.elem.children('style')[0];
|
||||||
|
var selector = '.' + FIXED_HEIGHT_PATCH;
|
||||||
|
|
||||||
|
trsElem.toggleClass(FIXED_HEIGHT_PATCH, isEnter);
|
||||||
|
// 将当前鼠标悬停行的高度同步到 FIXED_HEIGHT_PATCH (所有区域)类名的样式中
|
||||||
|
if (isEnter) {
|
||||||
|
lay.getStyleRules(style, function (item) {
|
||||||
|
if (item.selectorText === selector) {
|
||||||
|
item.style.setProperty('height', that.getElementSize(targetEl).height + 'px', 'important');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 将当前鼠标悬停行主区域的行高同步到固定列行
|
||||||
|
var height;
|
||||||
|
lay.getStyleRules(style, function (item) {
|
||||||
|
if (item.selectorText === selector) {
|
||||||
|
item.style.setProperty('height', 'auto');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
trsElem = trsElem.filter(function () {
|
||||||
|
var tr = $(this);
|
||||||
|
var isFixed = tr.closest(ELEM_FIXED, that.layBox).length > 0;
|
||||||
|
if (!isFixed) {
|
||||||
|
height = that.getElementSize(tr[0]).height;
|
||||||
|
}
|
||||||
|
return isFixed;
|
||||||
|
})
|
||||||
|
|
||||||
|
trsElem.css('height', height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Class.prototype.observeResize = function(){
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
if(!resizeObserver) return;
|
||||||
|
|
||||||
|
that.unobserveResize();
|
||||||
|
|
||||||
|
var el = that.elem[0];
|
||||||
|
var tableEl = that.layMain.children('table')[0];
|
||||||
|
// 显示或隐藏时重置列宽
|
||||||
|
resizeObserver.observe(el, $.proxy(that.resize, that));
|
||||||
|
|
||||||
|
// 同步固定列表格和主表格高度
|
||||||
|
var lineStyle = that.config.lineStyle;
|
||||||
|
var isAutoHeight = lineStyle && /\bheight\s*:\s*auto\b/g.test(lineStyle);
|
||||||
|
// 只重载数据时需要主动同步高度,因为 tbody 大小可能不变
|
||||||
|
var needSyncFixedRowHeight = that.needSyncFixedRowHeight = (that.layBody.length > 1) && (that.config.syncFixedRowHeight || (that.config.syncFixedRowHeight !== false && isAutoHeight));
|
||||||
|
|
||||||
|
if(needSyncFixedRowHeight){
|
||||||
|
resizeObserver.observe(
|
||||||
|
tableEl,
|
||||||
|
$.proxy(that.calcFixedRowHeight, that)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
that.unobserveResize = function(){
|
||||||
|
resizeObserver.unobserve(el);
|
||||||
|
if(needSyncFixedRowHeight){
|
||||||
|
resizeObserver.unobserve(tableEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
that.unobserveResize = $.noop;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 全局事件
|
// 全局事件
|
||||||
(function(){
|
(function(){
|
||||||
// 自适应尺寸
|
// 自适应尺寸
|
||||||
|
|
Loading…
Reference in New Issue