Skip to content

Commit

Permalink
Table: optimize performance (#21330)
Browse files Browse the repository at this point in the history
* Table: optimize performance

* Table: fix sync height
  • Loading branch information
cs1707 authored Nov 18, 2021
1 parent 6baf6dc commit 13d48cf
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 81 deletions.
11 changes: 6 additions & 5 deletions packages/table/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ export const cellForced = {
on-input={ this.toggleAllSelection }
value={ this.isAllSelected } />;
},
renderCell: function(h, { row, column, store, $index }) {
renderCell: function(h, { row, column, isSelected, store, $index }) {
return <el-checkbox
nativeOn-click={ (event) => event.stopPropagation() }
value={ store.isSelected(row) }
value={ isSelected }
disabled={ column.selectable ? !column.selectable.call(null, row, $index) : false }
on-input={ () => { store.commit('rowSelectedChanged', row); } } />;
on-input={ () => { store.commit('rowSelectedChanged', row); } }
/>;
},
sortable: false,
resizable: false
Expand All @@ -67,9 +68,9 @@ export const cellForced = {
renderHeader: function(h, { column }) {
return column.label || '';
},
renderCell: function(h, { row, store }) {
renderCell: function(h, { row, store, isExpanded }) {
const classes = ['el-table__expand-icon'];
if (store.states.expandRows.indexOf(row) > -1) {
if (isExpanded) {
classes.push('el-table__expand-icon--expanded');
}
const callback = function(e) {
Expand Down
6 changes: 6 additions & 0 deletions packages/table/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ Watcher.prototype.mutations = {
}

this.updateTableScrollY();
this.syncFixedTableRowHeight();
},

filterChange(states, options) {
Expand All @@ -111,6 +112,7 @@ Watcher.prototype.mutations = {
}

this.updateTableScrollY();
this.syncFixedTableRowHeight();
},

toggleAllSelection() {
Expand Down Expand Up @@ -144,4 +146,8 @@ Watcher.prototype.updateTableScrollY = function() {
Vue.nextTick(this.table.updateScrollY);
};

Watcher.prototype.syncFixedTableRowHeight = function() {
Vue.nextTick(() => this.table.layout.syncFixedTableRowHeight());
};

export default Watcher;
145 changes: 72 additions & 73 deletions packages/table/src/table-body.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ElTooltip from 'element-ui/packages/tooltip';
import debounce from 'throttle-debounce/debounce';
import LayoutObserver from './layout-observer';
import { mapStates } from './store/helper';
import TableRow from './table-row.js';

export default {
name: 'ElTableBody',
Expand All @@ -14,7 +15,8 @@ export default {

components: {
ElCheckbox,
ElTooltip
ElTooltip,
TableRow
},

props: {
Expand All @@ -39,16 +41,25 @@ export default {
border="0">
<colgroup>
{
this.columns.map(column => <col name={ column.id } key={column.id} />)
this.columns
.filter((column, index) => !(this.columnsHidden[index] && this.fixed))
.map(column => <col name={column.id} key={column.id} />)
}
</colgroup>
<tbody>
{
data.reduce((acc, row) => {
return acc.concat(this.wrappedRowRender(row, acc.length));
const isSelected = this.store.isSelected(row);
const isExpanded = this.store.states.expandRows.indexOf(row) > -1;
return acc.concat(this.wrappedRowRender({
row,
$index: acc.length,
isSelected,
isExpanded
}));
}, [])
}
<el-tooltip effect={ this.table.tooltipEffect } placement="top" ref="tooltip" content={ this.tooltipContent }></el-tooltip>
<el-tooltip effect={this.table.tooltipEffect} placement="top" ref="tooltip" content={this.tooltipContent}></el-tooltip>
</tbody>
</table>
);
Expand All @@ -71,6 +82,10 @@ export default {
hasExpandColumn: states => states.columns.some(({ type }) => type === 'expand')
}),

columnsHidden() {
return this.columns.map((column, index) => this.isColumnHidden(index));
},

firstDefaultColumnIndex() {
return arrayFindIndex(this.columns, ({ type }) => type === 'default');
}
Expand Down Expand Up @@ -238,7 +253,7 @@ export default {

if (cell) {
const column = getColumnByCell(table, cell);
const hoverState = table.hoverState = {cell, column, row};
const hoverState = table.hoverState = { cell, column, row };
table.$emit('cell-mouse-enter', hoverState.row, hoverState.column, hoverState.cell, event);
}

Expand Down Expand Up @@ -314,9 +329,18 @@ export default {
table.$emit(`row-${name}`, row, column, event);
},

rowRender(row, $index, treeRowData) {
getRowHeight(rowKey) {
const { fixed } = this;
if (!fixed) {
return null;
}
const height = (this.tableLayout.fixedColumnsBodyRowsHeight || {})[rowKey];
return typeof height === 'number' ? `${height}px` : height;
},

rowRender({ row, $index, treeRowData, isSelected, isExpanded }) {
const { treeIndent, columns, firstDefaultColumnIndex } = this;
const columnsHidden = columns.map((column, index) => this.isColumnHidden(index));

const rowClasses = this.getRowClass(row, $index);
let display = true;
if (treeRowData) {
Expand All @@ -328,76 +352,51 @@ export default {
let displayStyle = display ? null : {
display: 'none'
};
return (<tr
style={ [displayStyle, this.getRowStyle(row, $index)] }
class={ rowClasses }
key={ this.getKeyOfRow(row, $index) }
on-dblclick={ ($event) => this.handleDoubleClick($event, row) }
on-click={ ($event) => this.handleClick($event, row) }
on-contextmenu={ ($event) => this.handleContextMenu($event, row) }
on-mouseenter={ _ => this.handleMouseEnter($index) }
on-mouseleave={ this.handleMouseLeave }>
{
columns.map((column, cellIndex) => {
const { rowspan, colspan } = this.getSpan(row, column, $index, cellIndex);
if (!rowspan || !colspan) {
return null;
}
const columnData = { ...column };
columnData.realWidth = this.getColspanRealWidth(columns, colspan, cellIndex);
const data = {
store: this.store,
_self: this.context || this.table.$vnode.context,
column: columnData,
row,
$index
};
if (cellIndex === firstDefaultColumnIndex && treeRowData) {
data.treeNode = {
indent: treeRowData.level * treeIndent,
level: treeRowData.level
};
if (typeof treeRowData.expanded === 'boolean') {
data.treeNode.expanded = treeRowData.expanded;
// 表明是懒加载
if ('loading' in treeRowData) {
data.treeNode.loading = treeRowData.loading;
}
if ('noLazyChildren' in treeRowData) {
data.treeNode.noLazyChildren = treeRowData.noLazyChildren;
}
}
}
return (
<td
style={ this.getCellStyle($index, cellIndex, row, column) }
class={ this.getCellClass($index, cellIndex, row, column) }
rowspan={ rowspan }
colspan={ colspan }
on-mouseenter={ ($event) => this.handleCellMouseEnter($event, row) }
on-mouseleave={ this.handleCellMouseLeave }>
{
column.renderCell.call(
this._renderProxy,
this.$createElement,
data,
columnsHidden[cellIndex]
)
}
</td>
);
})
}
</tr>);
const height = this.getRowHeight($index);
const heightStyle = height ? {
height
} : null;

return (
<TableRow
style={[displayStyle, this.getRowStyle(row, $index), heightStyle]}
class={rowClasses}
key={this.getKeyOfRow(row, $index)}
nativeOn-dblclick={($event) => this.handleDoubleClick($event, row)}
nativeOn-click={($event) => this.handleClick($event, row)}
nativeOn-contextmenu={($event) => this.handleContextMenu($event, row)}
nativeOn-mouseenter={_ => this.handleMouseEnter($index)}
nativeOn-mouseleave={this.handleMouseLeave}
columns={columns}
row={row}
index={$index}
store={this.store}
context={this.context || this.table.$vnode.context}
firstDefaultColumnIndex={firstDefaultColumnIndex}
treeRowData={treeRowData}
treeIndent={treeIndent}
columnsHidden={this.columnsHidden}
getSpan={this.getSpan}
getColspanRealWidth={this.getColspanRealWidth}
getCellStyle={this.getCellStyle}
getCellClass={this.getCellClass}
handleCellMouseEnter={this.handleCellMouseEnter}
handleCellMouseLeave={this.handleCellMouseLeave}
isSelected={isSelected}
isExpanded={isExpanded}
fixed={this.fixed}
>
</TableRow>
);
},

wrappedRowRender(row, $index) {
wrappedRowRender({ row, $index, isSelected, isExpanded }) {
const store = this.store;
const { isRowExpanded, assertRowKey } = store;
const { treeData, lazyTreeNodeMap, childrenColumnName, rowKey } = store.states;
if (this.hasExpandColumn && isRowExpanded(row)) {
const renderExpanded = this.table.renderExpanded;
const tr = this.rowRender(row, $index);
const tr = this.rowRender({ row, $index, isSelected, isExpanded });
if (!renderExpanded) {
console.error('[Element Error]renderExpanded is required.');
return tr;
Expand Down Expand Up @@ -430,7 +429,7 @@ export default {
treeRowData.loading = cur.loading;
}
}
const tmp = [this.rowRender(row, $index, treeRowData)];
const tmp = [this.rowRender({ row, $index, treeRowData, isSelected, isExpanded })];
// 渲染嵌套数据
if (cur) {
// currentRow 记录的是 index,所以还需主动增加 TreeTable 的 index
Expand Down Expand Up @@ -464,7 +463,7 @@ export default {
}
}
i++;
tmp.push(this.rowRender(node, $index + i, innerTreeRowData));
tmp.push(this.rowRender({ row: node, $index: $index + i, treeRowData: innerTreeRowData, isSelected, isExpanded }));
if (cur) {
const nodes = lazyTreeNodeMap[childKey] || node[childrenColumnName];
traverse(nodes, cur);
Expand All @@ -478,7 +477,7 @@ export default {
}
return tmp;
} else {
return this.rowRender(row, $index);
return this.rowRender({ row, $index, isSelected, isExpanded });
}
}
}
Expand Down
32 changes: 31 additions & 1 deletion packages/table/src/table-layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class TableLayout {
this.bodyHeight = null; // Table Height - Table Header Height
this.fixedBodyHeight = null; // Table Height - Table Header Height - Scroll Bar Height
this.gutterWidth = scrollbarWidth();
this.fixedColumnsBodyRowsHeight = {};

for (let name in options) {
if (options.hasOwnProperty(name)) {
Expand Down Expand Up @@ -113,11 +114,40 @@ class TableLayout {

const noData = !(this.store.states.data && this.store.states.data.length);
this.viewportHeight = this.scrollX ? tableHeight - (noData ? 0 : this.gutterWidth) : tableHeight;

setTimeout(() => {
this.syncFixedTableRowHeight();
});
this.updateScrollY();
this.notifyObservers('scrollable');
}

syncFixedTableRowHeight() {
const fixedColumns = this.store.states.fixedColumns;
const rightFixedColumns = this.store.states.rightFixedColumns;
if (fixedColumns.length + rightFixedColumns.length === 0) {
return;
}
const { bodyWrapper } = this.table.$refs;
const tableRect = bodyWrapper.getBoundingClientRect();

if (tableRect.height !== undefined && tableRect.height <= 0) {
return;
}
const bodyRows = bodyWrapper.querySelectorAll('.el-table__row') || [];

const fixedColumnsBodyRowsHeight = [].reduce.call(
bodyRows,
(acc, row, index) => {
const height =
row.getBoundingClientRect().height || 'auto';
acc[index] = height;
return acc;
},
{}
);
this.fixedColumnsBodyRowsHeight = fixedColumnsBodyRowsHeight;
};

headerDisplayNone(elm) {
if (!elm) return true;
let headerChild = elm;
Expand Down
Loading

0 comments on commit 13d48cf

Please sign in to comment.