refactor: extract image reveal logic and improve GSAP loading reliability

Signed-off-by: Sped0n <hi@sped0n.com>
This commit is contained in:
Sped0n
2026-03-22 17:30:41 +08:00
parent 797b59a38a
commit 1c386386f3

View File

@@ -1,4 +1,5 @@
import { onMount, type JSX } from 'solid-js'
import { type gsap } from 'gsap'
import { createEffect, on, onMount, type JSX } from 'solid-js'
import invariant from 'tiny-invariant'
import type { ImageJSON } from '../resources'
@@ -14,27 +15,39 @@ export default function GalleryImage(props: {
let img: HTMLImageElement | undefined
let loadingDiv: HTMLDivElement | undefined
let _gsap: typeof gsap
let _gsap: typeof gsap | undefined
let gsapPromise: Promise<typeof gsap> | undefined
let revealed = false
const [state] = useState()
onMount(() => {
loadGsap()
.then((g) => {
_gsap = g
})
.catch((e) => {
console.log(e)
})
img?.addEventListener(
'load',
() => {
const revealImage = async (): Promise<void> => {
if (revealed) return
revealed = true
invariant(img, 'ref must be defined')
invariant(loadingDiv, 'loadingDiv must be defined')
gsapPromise ??= loadGsap()
try {
_gsap ??= await gsapPromise
} catch (e) {
console.log(e)
}
if (_gsap === undefined) {
img.style.opacity = '1'
loadingDiv.style.opacity = '0'
return
}
if (state().index !== props.ij.index) {
_gsap.set(img, { opacity: 1 })
_gsap.set(loadingDiv, { opacity: 0 })
} else {
return
}
_gsap.to(img, {
opacity: 1,
delay: 0.5,
@@ -43,11 +56,42 @@ export default function GalleryImage(props: {
})
_gsap.to(loadingDiv, { opacity: 0, duration: 0.5, ease: 'power3.in' })
}
onMount(() => {
gsapPromise = loadGsap()
.then((g) => {
_gsap = g
return g
})
.catch((e) => {
console.log(e)
throw e
})
img?.addEventListener(
'load',
() => {
void revealImage()
},
{ once: true, passive: true }
)
if (props.load && img?.complete && img.currentSrc !== '') {
void revealImage()
}
})
createEffect(
on(
() => props.load,
(load) => {
if (!load || img === undefined || !img.complete || img.currentSrc === '') return
void revealImage()
},
{ defer: true }
)
)
return (
<>
<div class="slideContainer">