expo-duooomi-app/@share/components/Img.tsx

113 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Image as ExpoImage, type ImageProps as ExpoImageProps } from 'expo-image'
import React, { forwardRef, useMemo } from 'react'
import { TouchableOpacity, type TouchableOpacityProps } from 'react-native'
import tw from 'twrnc'
interface ImgProps extends ExpoImageProps {
onClick?: () => void
touchProps?: TouchableOpacityProps
className?: string
src?: string | number
errorSource?: string | number
/** 自定义缓存键,用于需要重定向的 URL */
cacheKey?: string
}
const Img = forwardRef<ExpoImage, ImgProps>((props, ref) => {
const {
onClick,
touchProps = {},
className = '',
style = {},
src,
errorSource,
source: propSource,
cacheKey,
...reset
} = props
const imageStyle = tw`${className}`
// 判断是否为网络图片
const isNetworkImage = (uri: string | number): boolean => {
if (typeof uri !== 'string') return false
return uri.startsWith('http://') || uri.startsWith('https://')
}
// 自动从 URL 提取稳定的缓存键
const extractCacheKey = (url: string): string => {
try {
const urlObj = new URL(url)
// 使用路径部分作为缓存键忽略查询参数token、签名等
return urlObj.pathname
} catch {
// URL 解析失败时使用原始 URL
return url
}
}
// 构建图片源
const imageSource = useMemo(() => {
// 如果提供了source属性优先使用
if (propSource) return propSource
if (!src) return undefined
if (typeof src === 'number') {
// 本地图片资源require导入的资源ID
return src
} else {
// 网络图片或本地文件路径
if (isNetworkImage(src)) {
// 自动提取缓存键:优先使用传入的 cacheKey否则从 URL 路径自动提取
const autoCacheKey = cacheKey || extractCacheKey(src)
return {
uri: src,
cacheKey: autoCacheKey,
}
} else {
// 本地文件路径
return { uri: src }
}
}
}, [src, propSource, cacheKey])
const imgProps = {
style: [style, imageStyle],
ref,
// placeholder: blurhash,
source: imageSource,
cachePolicy: 'disk' as const,
errorSource,
...reset,
}
const handlePress = () => {
onClick && onClick()
}
if (onClick) {
return (
<TouchableOpacity onPress={handlePress} {...touchProps}>
<ExpoImage
{...imgProps}
transition={{ duration: 200, effect: 'cross-dissolve' }}
// onLoad={(event) => {
// const { cacheType } = event
// console.log('缓存类型:', cacheType)
// // cacheType 可能的值:
// // - 'none' - 没有使用缓存,从网络加载
// // - 'disk' - 从磁盘缓存加载
// // - 'memory' - 从内存缓存加载
// }}
/>
</TouchableOpacity>
)
}
return <ExpoImage {...imgProps} />
})
Img.displayName = 'Img'
export default Img