mirror of
https://github.com/nextcloud/server.git
synced 2026-06-11 01:30:50 -04:00
perf(files): reuse keys for virtual scrolling
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
This commit is contained in:
parent
16975ae457
commit
c4b8abd343
1 changed files with 35 additions and 6 deletions
|
|
@ -16,8 +16,8 @@
|
|||
:class="gridMode ? 'files-list__tbody--grid' : 'files-list__tbody--list'"
|
||||
data-cy-files-list-tbody>
|
||||
<component :is="dataComponent"
|
||||
v-for="(item, i) in renderedItems"
|
||||
:key="i"
|
||||
v-for="({key, item}, i) in renderedItems"
|
||||
:key="key"
|
||||
:visible="(i >= bufferItems || index <= bufferItems) && (i < shownItems - bufferItems)"
|
||||
:source="item"
|
||||
:index="i"
|
||||
|
|
@ -34,13 +34,18 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { File, Folder } from '@nextcloud/files'
|
||||
import type { File, Folder, Node } from '@nextcloud/files'
|
||||
import { debounce } from 'debounce'
|
||||
import Vue, { PropType } from 'vue'
|
||||
|
||||
import filesListWidthMixin from '../mixins/filesListWidth.ts'
|
||||
import logger from '../logger.js'
|
||||
|
||||
interface RecycledPoolItem {
|
||||
key: string,
|
||||
item: Node,
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'VirtualList',
|
||||
|
||||
|
|
@ -98,7 +103,8 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
itemHeight() {
|
||||
// 160px + 44px (name) + 15px (grid gap)
|
||||
// Align with css in FilesListVirtual
|
||||
// 138px + 44px (name) + 15px (grid gap)
|
||||
return this.gridMode ? (160 + 44 + 15) : 56
|
||||
},
|
||||
// Grid mode only
|
||||
|
|
@ -128,11 +134,32 @@ export default Vue.extend({
|
|||
|
||||
return this.rowCount
|
||||
},
|
||||
renderedItems(): (File | Folder)[] {
|
||||
renderedItems(): RecycledPoolItem[] {
|
||||
if (!this.isReady) {
|
||||
return []
|
||||
}
|
||||
return this.dataSources.slice(this.startIndex, this.startIndex + this.shownItems)
|
||||
|
||||
const items = this.dataSources.slice(this.startIndex, this.startIndex + this.shownItems) as Node[]
|
||||
|
||||
const oldItems = items.filter(item => Object.values(this.$_recycledPool).includes(item[this.dataKey]))
|
||||
const oldItemsKeys = oldItems.map(item => item[this.dataKey] as string)
|
||||
const unusedKeys = Object.keys(this.$_recycledPool).filter(key => !oldItemsKeys.includes(this.$_recycledPool[key]))
|
||||
|
||||
return items.map(item => {
|
||||
const index = Object.values(this.$_recycledPool).indexOf(item[this.dataKey])
|
||||
// If defined, let's keep the key
|
||||
if (index !== -1) {
|
||||
return {
|
||||
key: Object.keys(this.$_recycledPool)[index],
|
||||
item,
|
||||
}
|
||||
}
|
||||
|
||||
// Get and consume reusable key or generate a new one
|
||||
const key = unusedKeys.pop() || Math.random().toString(36).substr(2)
|
||||
this.$_recycledPool[key] = item[this.dataKey]
|
||||
return { key, item }
|
||||
})
|
||||
},
|
||||
|
||||
tbodyStyle() {
|
||||
|
|
@ -174,6 +201,8 @@ export default Vue.extend({
|
|||
if (this.scrollToIndex) {
|
||||
this.$el.scrollTop = Math.floor((this.index * this.itemHeight) / this.rowCount) + this.beforeHeight
|
||||
}
|
||||
|
||||
this.$_recycledPool = {} as Record<string, any>
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue