refactor: optimize Keep-Alive component rendering and data synchronization by introducing silent refresh states and fallback layout calculations.

This commit is contained in:
jxxghp
2026-05-17 14:06:05 +08:00
parent 348ae6b313
commit 0e005c3c7e
13 changed files with 197 additions and 78 deletions

View File

@@ -14,7 +14,7 @@ import { useI18n } from 'vue-i18n'
import { useBackground } from '@/composables/useBackground'
import { usePWA } from '@/composables/usePWA'
import { useAvailableHeight } from '@/composables/useAvailableHeight'
import { useKeepAliveRefresh } from '@/composables/useKeepAliveRefresh'
import { useKeepAliveRefresh, type KeepAliveRefreshContext } from '@/composables/useKeepAliveRefresh'
// 国际化
const { t } = useI18n()
@@ -234,11 +234,15 @@ function changeSelectMode() {
}
// 调API加载文件夹内的内容
async function list_files() {
loading.value = true
const takeURISnapshot = () => [inProps.item.storage, inProps.item.path].join(':/');
const prevURI = takeURISnapshot();
emit('loading', true)
async function list_files(context: KeepAliveRefreshContext = {}) {
const silentRefresh = Boolean(context.silent && items.value.length > 0)
const takeURISnapshot = () => [inProps.item.storage, inProps.item.path].join(':/')
const prevURI = takeURISnapshot()
if (!silentRefresh) {
loading.value = true
emit('loading', true)
}
try {
// 参数
@@ -264,8 +268,10 @@ async function list_files() {
} catch (error) {
console.error(error)
} finally {
emit('loading', false)
loading.value = false
if (!silentRefresh) {
emit('loading', false)
loading.value = false
}
}
}
@@ -673,10 +679,6 @@ function stopLoadingProgress() {
progressSSE.stop()
}
onMounted(() => {
list_files()
})
useKeepAliveRefresh(list_files, {
active: computed(() => inProps.active),
})

View File

@@ -260,6 +260,15 @@ function getComparableKey(item: any, index: number): ItemKey {
return index
}
function getFallbackLayoutWidth() {
if (typeof window === 'undefined') {
return safeMinItemWidth.value
}
// keep-alive 激活首帧可能还拿不到网格宽度,先用视口宽度兜底,避免只渲染一小列。
return Math.max(document.documentElement.clientWidth || window.innerWidth || 0, safeMinItemWidth.value)
}
function findFirstRowAtOrAfterOffset(offsets: number[], heights: number[], offset: number) {
let low = 0
let high = heights.length - 1
@@ -547,19 +556,31 @@ function syncLayoutWidth() {
const element = trackRef.value
if (!element) {
layoutWidth.value = 0
if (layoutWidth.value <= 0) {
layoutWidth.value = getFallbackLayoutWidth()
}
return
}
layoutWidth.value = element.clientWidth
const nextWidth = element.clientWidth
if (nextWidth > 0) {
layoutWidth.value = nextWidth
return
}
if (layoutWidth.value <= 0) {
layoutWidth.value = getFallbackLayoutWidth()
}
}
function syncViewport() {
const element = trackRef.value
if (!element) {
viewportTop.value = 0
viewportBottom.value = 0
if (viewportBottom.value <= viewportTop.value) {
viewportTop.value = 0
viewportBottom.value = typeof window === 'undefined' ? 0 : window.innerHeight
}
return
}
@@ -572,8 +593,13 @@ function syncViewport() {
top: 0,
}
viewportTop.value = viewportRect.top - trackRect.top
viewportBottom.value = viewportRect.bottom - trackRect.top
const nextViewportTop = viewportRect.top - trackRect.top
const nextViewportBottom = viewportRect.bottom - trackRect.top
if (nextViewportBottom > nextViewportTop) {
viewportTop.value = nextViewportTop
viewportBottom.value = nextViewportBottom
}
}
function queueLayoutSync() {
@@ -800,6 +826,7 @@ onActivated(() => {
mounted = true
refreshScrollTarget()
queueLayoutSync()
requestAnimationFrame(queueLayoutSync)
})
onDeactivated(() => {

View File

@@ -60,6 +60,15 @@ const trailingSpaceWidth = computed(() => {
return Math.max(totalContentWidth.value - leadingSpaceWidth.value - visibleItemsWidth.value, 0)
})
function getFallbackViewportWidth() {
if (typeof window === 'undefined') {
return itemStep.value * Math.max(props.overscanItems, 1)
}
// keep-alive 激活的首帧偶尔测不到容器宽度,先按视口宽度渲染一屏,避免右侧短暂空白。
return Math.max(window.innerWidth, itemStep.value * Math.max(props.overscanItems, 1))
}
function resolveItemKey(item: any, index: number) {
if (props.getItemKey) {
return props.getItemKey(item, startIndex.value + index)
@@ -87,7 +96,7 @@ function updateVisibleRange() {
return
}
const viewportWidth = element.clientWidth
const viewportWidth = element.clientWidth || getFallbackViewportWidth()
if (!viewportWidth || !props.items.length) {
startIndex.value = 0
endIndex.value = Math.min(props.items.length, props.overscanItems)
@@ -185,6 +194,7 @@ onActivated(() => {
}
nextTick(syncLayoutState)
requestAnimationFrame(syncLayoutState)
})
watch(