From c804b8b584fa0bf3d3c97c80fbaba2802ee89afd Mon Sep 17 00:00:00 2001 From: redhoodsu Date: Thu, 14 Nov 2024 11:59:34 +0800 Subject: [PATCH] perf(data-grid): append a lot --- src/data-grid/index.ts | 61 +++++++++++++++++++++++++++++++----------- src/data-grid/story.js | 49 ++++++++++++++++----------------- 2 files changed, 71 insertions(+), 39 deletions(-) diff --git a/src/data-grid/index.ts b/src/data-grid/index.ts index 76e7459..fb2b3fe 100644 --- a/src/data-grid/index.ts +++ b/src/data-grid/index.ts @@ -63,6 +63,8 @@ export interface IDataGridNodeOptions { selectable?: boolean } +const MIN_APPEND_INTERVAL = 100 + /** * Grid for displaying datasets. * @@ -102,11 +104,14 @@ export default class DataGrid extends Component { private onResize: () => void private tableBody: HTMLElement private nodes: DataGridNode[] = [] + private displayNodes: DataGridNode[] = [] private colWidthsInitialized = false private colMap: types.PlainObj = {} private sortId?: string private selectedNode: DataGridNode | null = null private isAscending = true + private appendTimer: NodeJS.Timeout | null = null + private frag: DocumentFragment = document.createDocumentFragment() private colWidths: number[] = [] constructor(container: HTMLElement, options: IOptions) { super(container, { compName: 'data-grid' }, options) @@ -179,21 +184,34 @@ export default class DataGrid extends Component { const node = new DataGridNode(this, data, options) this.nodes.push(node) + const isVisible = this.filterNode(node) + if (isVisible) { + this.displayNodes.push(node) + } + if (this.sortId) { this.sortNodes(this.sortId, this.isAscending) } else { - if (this.filterNode(node)) { - this.tableBody.insertBefore(node.container, this.fillerRow) - this.updateHeight() + if (isVisible) { + this.frag.appendChild(node.container) + if (!this.appendTimer) { + this.appendTimer = setTimeout(this._append, MIN_APPEND_INTERVAL) + } } } return node } + private _append = () => { + this.tableBody.insertBefore(this.frag, this.fillerRow) + this.appendTimer = null + this.updateHeight() + } /** Clear all data. */ clear() { - each(this.nodes, (node) => node.detach()) + this.detachAll() this.nodes = [] + this.displayNodes = [] this.selectNode(null) this.updateHeight() @@ -366,6 +384,15 @@ export default class DataGrid extends Component { this.updateHeight() break case 'filter': + this.displayNodes = [] + each(this.nodes, (node) => { + if (this.filterNode(node)) { + this.displayNodes.push(node) + } + }) + if (this.selectedNode && !this.filterNode(this.selectedNode)) { + this.selectNode(null) + } this.renderData() break } @@ -375,7 +402,7 @@ export default class DataGrid extends Component { const column = this.colMap[id] const comparator = column.comparator || naturalOrderComparator - this.nodes.sort(function (a, b) { + function sortFn(a: DataGridNode, b: DataGridNode) { let aVal = a.data[id] let bVal = b.data[id] if (isEl(aVal)) { @@ -386,7 +413,9 @@ export default class DataGrid extends Component { } return isAscending ? comparator(aVal, bVal) : comparator(bVal, aVal) - }) + } + this.nodes.sort(sortFn) + this.displayNodes.sort(sortFn) this.renderData() @@ -460,20 +489,22 @@ export default class DataGrid extends Component { } } private renderData() { - const { tableBody, nodes, fillerRow } = this + const { tableBody, displayNodes, fillerRow } = this - each(nodes, (node) => node.detach()) - each(nodes, (node) => { - if (this.filterNode(node)) { - tableBody.insertBefore(node.container, fillerRow) - } + this.detachAll() + const frag = document.createDocumentFragment() + each(displayNodes, (node) => { + frag.appendChild(node.container) }) - if (this.selectedNode && !this.filterNode(this.selectedNode)) { - this.selectNode(null) - } + tableBody.insertBefore(frag, fillerRow) this.updateHeight() } + private detachAll() { + const { tableBody } = this + tableBody.innerHTML = '' + tableBody.appendChild(this.fillerRow) + } private filterNode(node: DataGridNode) { let { filter } = this.options diff --git a/src/data-grid/story.js b/src/data-grid/story.js index 45a3e30..9022d3e 100644 --- a/src/data-grid/story.js +++ b/src/data-grid/story.js @@ -11,10 +11,10 @@ import { object, number, button, text } from '@storybook/addon-knobs' const def = story( 'data-grid', (container) => { - const { columns, maxHeight, minHeight, filter } = createKnobs() + const { maxHeight, minHeight, filter } = createKnobs() const dataGrid = new DataGrid(container, { - columns, + columns: getColumns(), maxHeight, minHeight, filter, @@ -44,7 +44,7 @@ const def = story( changelog, source: __STORY__, ReactComponent() { - const { columns, minHeight, maxHeight, filter } = createKnobs() + const { minHeight, maxHeight, filter } = createKnobs() return ( { console.log('deselect') }} - columns={columns} + columns={getColumns()} minHeight={minHeight} maxHeight={maxHeight} filter={filter} @@ -65,6 +65,27 @@ const def = story( } ) +function getColumns() { + return [ + { + id: 'index', + title: 'Index', + weight: 20, + sortable: true, + }, + { + id: 'name', + title: 'Name', + sortable: true, + weight: 30, + }, + { + id: 'site', + title: 'Site', + }, + ] +} + function getData() { return [ { @@ -111,25 +132,6 @@ function getData() { } function createKnobs() { - const columns = object('Columns', [ - { - id: 'index', - title: 'Index', - weight: 20, - sortable: true, - }, - { - id: 'name', - title: 'Name', - sortable: true, - weight: 30, - }, - { - id: 'site', - title: 'Site', - }, - ]) - const minHeight = number('Min Height', 80, { range: true, min: 23, @@ -144,7 +146,6 @@ function createKnobs() { const filter = text('Filter', '') return { - columns, minHeight, maxHeight, filter,