Skip to content

Commit

Permalink
feat(data-table): supports horizontal virtual scrolling
Browse files Browse the repository at this point in the history
  • Loading branch information
07akioni committed Sep 23, 2024
1 parent 2e45347 commit 17b96c9
Show file tree
Hide file tree
Showing 12 changed files with 821 additions and 354 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"treemate": "^0.3.11",
"vdirs": "^0.1.8",
"vooks": "^0.2.12",
"vueuc": "^0.4.58"
"vueuc": "^0.4.63"
},
"devDependencies": {
"@antfu/eslint-config": "^2.22.0",
Expand Down
1 change: 1 addition & 0 deletions src/data-table/demos/enUS/index.demo-entry.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ render-header
custom-style.vue
ajax-usage
virtual.vue
virtual-x.vue
custom-filter-menu.vue
tree.vue
flex-height.vue
Expand Down
82 changes: 82 additions & 0 deletions src/data-table/demos/enUS/virtual-x.demo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<markdown>
# Large data (rows & cols)

If you have a large amount of row and column data, such as thousands of rows and hundreds of columns, `naive-ui` provides horizontal + vertical virtual scrolling functionality.

Due to the inherent complexity of horizontal virtual scrolling, the corresponding configuration can be quite complex, with most of the following content being necessary:

1. Configure `virtual-scroll` to enable vertical virtual scrolling.
2. Configure `virtual-scroll-x` to enable horizontal virtual scrolling:
- Each column needs to have a `width` property configured.
- Configure the `scroll-x` property, setting it to the total width of all columns.
- Configure the `min-row-height` property, setting it to the minimum height of each row, where all rows must be larger than this value.
- Configure the `height-for-row` property, which is used to set the height of each row (since only a portion of the cells in each row are always visible, this cannot be automatically calculated). If not configured, the height of each row will be set to `min-row-height`.
3. If needed, configure `virtual-scroll-header`. By default, the header will still be fully rendered to maintain compatibility. You can enable virtual rendering for the header with this configuration:
- Configure the `header-height` property, setting it to the height of the header.

The example below corresponds to a table with 1000 rows * 1000 columns.

`naive-ui`'s table can easily support table data in the millions. You won't find this kind of functionality in many free component libraries.
</markdown>

<script lang="ts">
import { defineComponent } from 'vue'
import type { DataTableColumns } from 'naive-ui'
interface RowData {
key: number
name: string
age: number
address: string
}
const columns: DataTableColumns<RowData> = []
let scrollX = 0
for (let i = 0; i < 1000; ++i) {
scrollX += 100
columns.push({
title: `Col ${i}`,
width: 100,
key: i,
fixed: i <= 1 ? 'left' : i > 997 ? 'right' : undefined,
render(_, rowIndex) {
return `${i}-${rowIndex}`
}
})
}
export default defineComponent({
setup() {
const data: RowData[] = Array.from({ length: 1000 }).map((_, index) => ({
key: index,
name: `Edward King ${index}`,
age: 32,
address: `London, Park Lane no. ${index}`
}))
return {
data,
columns,
scrollX,
minRowHeight: 48,
heightForRow: () => 48
}
}
})
</script>

<template>
<n-data-table
:columns="columns"
:data="data"
:max-height="250"
virtual-scroll
virtual-scroll-x
:scroll-x="scrollX"
:min-row-height="48"
:height-for-row="heightForRow"
virtual-scroll-header
:header-height="48"
/>
</template>
1 change: 1 addition & 0 deletions src/data-table/demos/zhCN/index.demo-entry.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ render-header
custom-style.vue
ajax-usage
virtual.vue
virtual-x.vue
custom-filter-menu.vue
tree.vue
flex-height.vue
Expand Down
82 changes: 82 additions & 0 deletions src/data-table/demos/zhCN/virtual-x.demo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<markdown>
# 大量数据(行和列)

如果你有大量行数据和列数据,例如几千行 + 几百列,`naive-ui` 提供了横向 + 纵向虚拟滚动的功能。

因为横向虚拟滚动的天然的复杂性,对应的配置也会较为复杂,以下多数内容都是必须的:

1. 配置 `virtual-scroll` 打开纵向虚拟滚动
2. 配置 `virtual-scroll-x` 打开横向虚拟滚动
- 每一个列都需要配置 `width` 属性
- 配置 `scroll-x` 属性,设为所有列的总宽度
- 配置 `min-row-height` 属性,设为每一列的最小高度,所有的列必须比这个值更大
- 配置 `height-for-row` 属性,用于配置每一行的高度(因为每一行永远只有一部分格子是可见的,因此无法自动求出),如果不配置,每一行的高度会被设为 `min-row-height`
3. 如有需要,配置 `virtual-scroll-header`,默认情况下,表头依然会全量渲染以保持兼容性,你可以通过此配置来打开表头的虚拟渲染
- 配置 `header-height` 属性,设为表头的高度

下面的例子对应了一个 1000 行 * 1000 列的表格。

`naive-ui` 的表格可以轻松的支持千万级的表格数据,你在不收钱的组件库不容易找得到这样的功能。
</markdown>

<script lang="ts">
import { defineComponent } from 'vue'
import type { DataTableColumns } from 'naive-ui'
interface RowData {
key: number
name: string
age: number
address: string
}
const columns: DataTableColumns<RowData> = []
let scrollX = 0
for (let i = 0; i < 1000; ++i) {
scrollX += 100
columns.push({
title: `Col ${i}`,
width: 100,
key: i,
fixed: i <= 1 ? 'left' : i > 997 ? 'right' : undefined,
render(_, rowIndex) {
return `${i}-${rowIndex}`
}
})
}
export default defineComponent({
setup() {
const data: RowData[] = Array.from({ length: 1000 }).map((_, index) => ({
key: index,
name: `Edward King ${index}`,
age: 32,
address: `London, Park Lane no. ${index}`
}))
return {
data,
columns,
scrollX,
minRowHeight: 48,
heightForRow: () => 48
}
}
})
</script>

<template>
<n-data-table
:columns="columns"
:data="data"
:max-height="250"
virtual-scroll
virtual-scroll-x
:scroll-x="scrollX"
:min-row-height="48"
:height-for-row="heightForRow"
virtual-scroll-header
:header-height="48"
/>
</template>
5 changes: 5 additions & 0 deletions src/data-table/src/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ export default defineComponent({
renderExpandRef,
summaryRef: toRef(props, 'summary'),
virtualScrollRef: toRef(props, 'virtualScroll'),
virtualScrollXRef: toRef(props, 'virtualScrollX'),
heightForRowRef: toRef(props, 'heightForRow'),
minRowHeightRef: toRef(props, 'minRowHeight'),
virtualScrollHeaderRef: toRef(props, 'virtualScrollHeader'),
headerHeightRef: toRef(props, 'headerHeight'),
rowPropsRef: toRef(props, 'rowProps'),
stripedRef: toRef(props, 'striped'),
checkOptionsRef: computed(() => {
Expand Down
8 changes: 7 additions & 1 deletion src/data-table/src/MainTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default defineComponent({
maxHeightRef,
minHeightRef,
flexHeightRef,
virtualScrollHeaderRef,
syncScrollState
} = inject(dataTableInjectionKey)!

Expand Down Expand Up @@ -47,7 +48,12 @@ export default defineComponent({
function getHeaderElement(): HTMLElement | null {
const { value } = headerInstRef
if (value) {
return value.$el
if (virtualScrollHeaderRef.value) {
return value.virtualListRef?.listElRef || null
}
else {
return value.$el
}
}
return null
}
Expand Down
Loading

0 comments on commit 17b96c9

Please sign in to comment.