perf(listings): 优化详情页图片加载链路支持公开变体与分级秒开

This commit is contained in:
yml2213
2026-09-06 21:40:35 +08:00
parent 823632b608
commit 23883d4be5
7 changed files with 168 additions and 11 deletions
@@ -40,6 +40,9 @@ import {
readAssetString,
getRatioValue,
isTopTierInsurance,
getScreenshotThumbURL,
getScreenshotMediumURL,
getScreenshotRawURL,
type ListingDisplayResource,
} from '@/shared/utils/listingDisplay'
@@ -165,7 +168,9 @@ const detailScreenshots = computed(() => {
url,
}))
})
const detailScreenshotUrls = computed(() => detailScreenshots.value.map(shot => shot.url))
const detailScreenshotRawUrls = computed(() =>
detailScreenshots.value.map(shot => getScreenshotRawURL(shot.url))
)
const activeScreenshot = computed(() => {
if (detailScreenshots.value.length === 0) return null
@@ -533,12 +538,12 @@ function goBack() {
<div class="gallery-stage">
<div v-if="activeScreenshot" class="stage-viewer">
<AuthImage
:source="activeScreenshot.url"
:source="getScreenshotMediumURL(activeScreenshot.url)"
:alt="activeScreenshot.label"
image-class="stage-image"
fallback-class="stage-image"
fit="contain"
:preview-src-list="detailScreenshotUrls"
:preview-src-list="detailScreenshotRawUrls"
:preview-initial-index="activeImageIndex"
/>
<!-- 左上角分类角标 -->
@@ -566,7 +571,7 @@ function goBack() {
@mouseenter="activeImageIndex = idx"
>
<AuthImage
:source="shot.url"
:source="getScreenshotThumbURL(shot.url)"
:alt="shot.label"
image-class="thumb-img"
fallback-class="thumb-img"
@@ -37,6 +37,9 @@ import {
readAssetString,
getRatioValue,
isTopTierInsurance,
getScreenshotThumbURL,
getScreenshotMediumURL,
getScreenshotRawURL,
} from '@/shared/utils/listingDisplay'
const route = useRoute()
@@ -164,7 +167,9 @@ const detailScreenshots = computed(() => {
url,
}))
})
const detailScreenshotUrls = computed(() => detailScreenshots.value.map(shot => shot.url))
const detailScreenshotRawUrls = computed(() =>
detailScreenshots.value.map(shot => getScreenshotRawURL(shot.url))
)
const activeScreenshot = computed(() => {
if (detailScreenshots.value.length === 0) return null
@@ -505,12 +510,12 @@ function handleToggleFavorite() {
<div class="gallery-stage">
<div v-if="activeScreenshot" class="stage-viewer">
<AuthImage
:source="activeScreenshot.url"
:source="getScreenshotMediumURL(activeScreenshot.url)"
:alt="activeScreenshot.label"
image-class="stage-image"
fallback-class="stage-image"
fit="contain"
:preview-src-list="detailScreenshotUrls"
:preview-src-list="detailScreenshotRawUrls"
:preview-initial-index="activeImageIndex"
/>
<span class="stage-tag">{{ activeScreenshot.label }}</span>
@@ -535,7 +540,7 @@ function handleToggleFavorite() {
@click="activeImageIndex = idx"
>
<AuthImage
:source="shot.url"
:source="getScreenshotThumbURL(shot.url)"
:alt="shot.label"
image-class="thumb-img"
fallback-class="thumb-img"
@@ -115,9 +115,27 @@ async function loadImage() {
const sourceURL = await resolveURL(props.source)
imageURL.value = sourceURL
if (props.previewSrcList?.length) {
previewURLs.value = await Promise.all(
props.previewSrcList.map(url => (url === props.source ? sourceURL : resolveURL(url)))
// 先填充公开或当前已解析的主图 URL,让预览组件立即可用
const initialPreviews = props.previewSrcList.map(url =>
url === props.source ? sourceURL : url
)
previewURLs.value = initialPreviews
// 若包含需要鉴权转 Blob 的私有 URL,在后台异步静默解析,不阻塞主图呈现
const hasAuthPreviews = props.previewSrcList.some(
url => url !== props.source && shouldFetchWithAuth(url)
)
if (hasAuthPreviews) {
Promise.all(
props.previewSrcList.map(url => (url === props.source ? sourceURL : resolveURL(url)))
)
.then(urls => {
previewURLs.value = urls
})
.catch(() => {
// 预览图静默降级,不破坏主图正常显示
})
}
}
} catch {
failed.value = true
@@ -416,3 +416,39 @@ export function isTopTierInsurance(value: string | undefined | null): boolean {
export function getCoinScreenshotURL(item: Listing): string {
return item.cover_url || item.screenshot_urls?.[0] || ''
}
/**
* 转换截图为缩略图 URL(优先使用 16KB 极速缩略图,秒级加载)
*/
export function getScreenshotThumbURL(url: string | undefined | null): string {
if (!url) return ''
if (url.includes('/screenshots/')) {
const separator = url.includes('?') ? '&' : '?'
return `${url}${separator}variant=thumb`
}
return url
}
/**
* 转换截图为中等图 URL(1280px,100KB左右,清晰秒开)
*/
export function getScreenshotMediumURL(url: string | undefined | null): string {
if (!url) return ''
if (url.includes('/screenshots/')) {
const separator = url.includes('?') ? '&' : '?'
return `${url}${separator}variant=medium`
}
return url
}
/**
* 转换截图为原始高清原图 URL(用于全屏放大查看细节)
*/
export function getScreenshotRawURL(url: string | undefined | null): string {
if (!url) return ''
if (url.includes('/screenshots/')) {
const separator = url.includes('?') ? '&' : '?'
return `${url}${separator}variant=raw`
}
return url
}