perf(glass): complete phase three optimization (#580)

This commit is contained in:
InfinityPacer
2026-07-23 20:26:28 +08:00
committed by GitHub
parent 31caf8f5f8
commit 1bf6c1f1d8
12 changed files with 277 additions and 89 deletions
+1
View File
@@ -464,6 +464,7 @@ onBeforeUnmount(() => {
class="app-hover-lift-card outline-none ring-gray-500 media-card"
:class="{
'app-hover-lift-card--hovering': isMediaCardActive(hover.isHovering),
'media-card--image-loaded': isImageLoaded,
'ring-1': isImageLoaded,
}"
@click.stop="handleMediaCardClick(hover.isHovering)"
@@ -520,8 +520,10 @@ onMounted(() => {
<input
ref="searchWordInput"
v-model="searchWord"
id="global-media-search"
type="text"
class="search-native-input"
:aria-label="t('dialog.searchBar.searchPlaceholder')"
:placeholder="t('dialog.searchBar.searchPlaceholder')"
@keydown.enter="searchMedia('media')"
@keydown.escape.stop="closeSearch"
@@ -539,8 +541,10 @@ onMounted(() => {
<input
ref="searchWordInput"
v-model="searchWord"
id="global-media-search"
type="text"
class="search-native-input"
:aria-label="t('dialog.searchBar.searchPlaceholder')"
:placeholder="t('dialog.searchBar.searchPlaceholder')"
@keydown.enter="searchMedia('media')"
@keydown.escape.stop="closeSearch"
@@ -43,6 +43,9 @@ describe('SearchBarDialog media source selection', () => {
const { router } = await renderSearchBar()
const input = await screen.findByPlaceholderText('搜索电影、剧集以及更多...')
expect(input.getAttribute('id')).toBe('global-media-search')
expect(input.getAttribute('aria-label')).toBe('搜索电影、剧集以及更多...')
await user.type(input, '流浪地球{Enter}')
await waitFor(() => {
+14 -27
View File
@@ -1,8 +1,8 @@
<script setup lang="ts">
import { findNearestScrollTarget, invalidateScrollTargetCache, type ScrollTarget } from '@/utils/scrollTarget'
import type { ComponentPublicInstance } from 'vue'
type ItemKey = string | number
type ScrollTarget = Window | HTMLElement
const props = withDefaults(
defineProps<{
@@ -513,19 +513,7 @@ function getItemRef(key: ItemKey) {
}
function findScrollTarget(): ScrollTarget {
let parent = containerRef.value?.parentElement ?? null
while (parent && parent !== document.body && parent !== document.documentElement) {
const overflowY = window.getComputedStyle(parent).overflowY
if (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay') {
return parent
}
parent = parent.parentElement
}
return window
return findNearestScrollTarget(containerRef.value)
}
function addScrollListener(target: ScrollTarget) {
@@ -552,6 +540,11 @@ function refreshScrollTarget() {
addScrollListener(scrollTarget)
}
function handleWindowResize() {
invalidateScrollTargetCache()
queueLayoutSync()
}
function syncLayoutWidth() {
const element = trackRef.value
@@ -780,10 +773,7 @@ function invalidateMeasurementsForLayoutChange() {
const nextColumnCount = columnCount.value
const nextColumnWidth = columnWidth.value
if (
lastMeasuredColumnCount === nextColumnCount &&
Math.abs(lastMeasuredColumnWidth - nextColumnWidth) < 1
) {
if (lastMeasuredColumnCount === nextColumnCount && Math.abs(lastMeasuredColumnWidth - nextColumnWidth) < 1) {
return
}
@@ -817,7 +807,7 @@ onMounted(() => {
})
}
window.addEventListener('resize', queueLayoutSync, { passive: true })
window.addEventListener('resize', handleWindowResize, { passive: true })
queueLayoutSync()
})
@@ -840,7 +830,7 @@ onUnmounted(() => {
removeScrollListener(scrollTarget)
scrollTarget = null
window.removeEventListener('resize', queueLayoutSync)
window.removeEventListener('resize', handleWindowResize)
resizeObserver?.disconnect()
resizeObserver = null
itemResizeObserver?.disconnect()
@@ -881,13 +871,10 @@ watch(
},
)
watch(
[columnCount, columnWidth],
() => {
invalidateMeasurementsForLayoutChange()
queueViewportSync()
},
)
watch([columnCount, columnWidth], () => {
invalidateMeasurementsForLayoutChange()
queueViewportSync()
})
watch(
[() => props.scrollToIndex, () => props.items.length, columnCount],