import { Image as ExpoImage, type ImageProps as ExpoImageProps } from 'expo-image' import React, { forwardRef, memo, useEffect, useMemo, useState } from 'react' import { View } from 'react-native' import tw from 'twrnc' interface ImgProps extends ExpoImageProps { className?: string src?: string | number width?: number isWebP?: boolean errorSource?: string | number isCompression?: boolean /** 自定义缓存键,用于需要重定向的 URL */ cacheKey?: string /** 占位图 URL,在真实图片加载完成前显示 */ placeholderSrc?: string autoPlay?: boolean } // ExpoImage.clearDiskCache() // ExpoImage.clearMemoryCache() // cloudflare 图片优化服务示例地址 const ImageOrigin = `https://bowong.cc/cdn-cgi/image/width=128,quality=75,format=webp/https://cdn.roasmax.cn/material/b59b75841c484d8bafec9c5636930b69.webp` const Img = forwardRef((props, ref) => { const { className = '', style = {}, src, source: propSource, cacheKey, width = 256, isCompression = false, isWebP = true, placeholderSrc, onLoad, ...reset } = props const [isLoaded, setIsLoaded] = useState(false) useEffect(() => { setIsLoaded(false) }, [src]) const imageStyle = tw`${className}` // 静态图全部压缩jpg const compressionUrl = useMemo(() => { const f = isWebP ? 'webp' : 'jpg' return `https://bowong.cc/cdn-cgi/image/width=${width},quality=75,format=${f}/${src}` }, [width, isWebP, src]) // 判断是否为网络图片 const isNetworkImage = (uri: string | number): boolean => { if (typeof uri !== 'string') return false return uri.startsWith('http://') || uri.startsWith('https://') } // 构建图片源 const imageSource = useMemo(() => { if (propSource) return propSource if (!src) return undefined if (typeof src === 'number') { return src } else { if (isNetworkImage(src)) { const finalUrl = isCompression ? compressionUrl : src return { uri: finalUrl, cacheKey: cacheKey || finalUrl, } } else { return { uri: src } } } }, [src, propSource, cacheKey, isCompression, compressionUrl]) const handleLoad = (e: any) => { // console.log('handleLoad--------------', e) setIsLoaded(true) onLoad?.(e) } // 无占位图时直接返回原图 if (!placeholderSrc) { return ( ) } const showPlaceholder = placeholderSrc // 有占位图时使用层叠布局 return ( {/* 占位图层 - 加载完成后隐藏 */} {showPlaceholder && ( )} {/* 真实图片层 */} ) }) Img.displayName = 'Img' export default memo(Img)