Skip to content

Commit

Permalink
fix(table): allow using virtual scroll with fixed column (#266) (#339)
Browse files Browse the repository at this point in the history
close #266

---------

Co-authored-by: Kia King Ishii <kia.king.08@gmail.com>
  • Loading branch information
brc-dd and kiaking committed Sep 12, 2023
1 parent 6bfe8bb commit 45ce637
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 73 deletions.
120 changes: 48 additions & 72 deletions lib/components/STable.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { useVirtualizer } from '@tanstack/vue-virtual'
import { useResizeObserver } from '@vueuse/core'
import {
computed,
Expand All @@ -9,7 +10,6 @@ import {
unref,
watch
} from 'vue'
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
import { type Table } from '../composables/Table'
import SSpinner from './SSpinner.vue'
import STableCell from './STableCell.vue'
Expand Down Expand Up @@ -111,14 +111,18 @@ const recordsWithSummary = computed(() => {
const records = unref(props.options.records) ?? []
const summary = unref(props.options.summary)
const res = summary ? [...records, summary] : records
return summary ? [...records, summary] : records
})
res.forEach((record, index) => {
record.__index = index
})
const virtualizerOptions = computed(() => ({
count: recordsWithSummary.value.length,
getScrollElement: () => body.value,
estimateSize: () => unref(props.options.rowSize) ?? 41,
overscan: 10
}))
return res
})
const rowVirtualizer = useVirtualizer(virtualizerOptions)
const virtualItems = computed(() => rowVirtualizer.value.getVirtualItems())
watch(() => props.options.records, () => {
headLock = true
Expand Down Expand Up @@ -272,75 +276,50 @@ function getCell(key: string, index: number) {
@mouseleave="lockBody(false)"
@scroll="syncBodyScroll"
>
<template v-if="unref(options.virtualScroll)">
<DynamicScroller
:items="recordsWithSummary"
:min-item-size="40"
key-field="__index"
class="block"
:style="blockWidth ? { width: `${blockWidth}px` } : undefined"
:prerender="Math.min(10, recordsWithSummary.length)"
>
<template #default="{ item: record, index: rIndex, active }">
<DynamicScrollerItem
:item="record"
:active="active"
:data-index="rIndex"
>
<div class="row" :class="isSummaryOrLastClass(rIndex)">
<STableItem
v-for="key in ordersToShow"
:key="key"
:name="key"
:class-name="unref(options.columns)[key].className"
:width="colWidths[key]"
>
<STableCell
:name="key"
:class="isSummary(rIndex) && 'summary'"
:class-name="unref(options.columns)[key].className"
:cell="getCell(key, rIndex)"
:value="record[key]"
:record="record"
:records="unref(options.records)!"
/>
</STableItem>
</div>
</DynamicScrollerItem>
</template>
</DynamicScroller>
</template>
<template v-else>
<div
class="block"
:style="{
width: blockWidth ? `${blockWidth}px` : '100%',
height: `${rowVirtualizer.getTotalSize()}px`,
position: 'relative'
}"
>
<div
class="block"
:style="blockWidth ? { width: `${blockWidth}px` } : undefined"
v-for="{ index, key: __key, size, start } in virtualItems"
:key="__key"
>
<div
v-for="(record, rIndex) in recordsWithSummary"
:key="record.__index"
class="row"
:class="isSummaryOrLastClass(index)"
:style="{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${size}px`,
transform: `translateY(${start}px)`
}"
>
<div class="row" :class="isSummaryOrLastClass(rIndex)">
<STableItem
v-for="key in ordersToShow"
:key="key"
<STableItem
v-for="key in ordersToShow"
:key="key"
:name="key"
:class-name="unref(options.columns)[key].className"
:width="colWidths[key]"
>
<STableCell
:name="key"
:class="isSummary(index) && 'summary'"
:class-name="unref(options.columns)[key].className"
:width="colWidths[key]"
>
<STableCell
:name="key"
:class="isSummary(rIndex) && 'summary'"
:class-name="unref(options.columns)[key].className"
:cell="getCell(key, rIndex)"
:value="record[key]"
:record="record"
:records="unref(options.records)!"
/>
</STableItem>
</div>
:cell="getCell(key, index)"
:value="recordsWithSummary[index][key]"
:record="recordsWithSummary[index]"
:records="unref(options.records)!"
/>
</STableItem>
</div>
</div>
</template>
</div>
</div>
</div>
Expand Down Expand Up @@ -417,14 +396,11 @@ function getCell(key: string, index: number) {
.container.body {
border-radius: 6px 6px var(--table-border-radius) var(--table-border-radius);
line-height: 0;
max-height: var(--table-max-height, 100%);
.STable.has-footer & {
border-radius: 0;
}
.block {
max-height: var(--table-max-height, 100%);
}
}
.block {
Expand Down
2 changes: 1 addition & 1 deletion lib/composables/Table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface Table<
reset?: MaybeRef<boolean | undefined>
borderless?: MaybeRef<boolean>
loading?: MaybeRef<boolean | undefined>
virtualScroll?: MaybeRef<boolean | undefined>
rowSize?: MaybeRef<number | undefined>
onPrev?(): void
onNext?(): void
onReset?(): void
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"peerDependencies": {
"@iconify-icons/ph": "^1.2.4",
"@iconify/vue": "^4.1.1",
"@tanstack/vue-virtual": "3.0.0-beta.60",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"@vueuse/core": "^10.4.1",
Expand All @@ -64,6 +65,7 @@
"@histoire/plugin-vue": "^0.17.1",
"@iconify-icons/ph": "^1.2.4",
"@iconify/vue": "^4.1.1",
"@tanstack/vue-virtual": "3.0.0-beta.60",
"@types/body-scroll-lock": "^3.1.0",
"@types/lodash-es": "^4.17.9",
"@types/markdown-it": "^13.0.1",
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 45ce637

Please sign in to comment.