You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
3.7 KiB
136 lines
3.7 KiB
import {FC, useEffect, useState} from "react";
|
|
import { Image, ImageProps, View } from "@tarojs/components";
|
|
import shard from '@/static/img/shard.png'
|
|
import Taro from "@tarojs/taro";
|
|
import avatar from '@/static/img/avatar.png'
|
|
import healthShard from '@/static/img/healthShard.png'
|
|
import professionShard from '@/static/img/professionShard.png'
|
|
import brandSecond from '@/static/img/brandSecond.png'
|
|
import courseShard from '@/static/img/courseShard.png'
|
|
import logo from '@/static/img/logo.svg'
|
|
|
|
interface Props extends ImageProps {
|
|
width?: number | string
|
|
height?: number | string
|
|
fallback?: string
|
|
errorType?: ImgErrType
|
|
loadingImage?: string
|
|
errorImage?: string
|
|
fit?: boolean // 当网络图片加载完成后高度自动
|
|
}
|
|
|
|
const Img: FC<Props> = ({src, mode = 'aspectFill', width, fallback = shard, ...props}) => {
|
|
const [isError, setIsError] = useState(false)
|
|
const [loading, setLoading] = useState(true)
|
|
const [errorUrl, setErrorUrl] = useState(fallback)
|
|
const [height, setHeight] = useState(props.height)
|
|
const imgAnimation = Taro.createAnimation({duration: 0}).opacity(0).step()
|
|
const [animationData, setAnimationData] = useState<TaroGeneral.IAnyObject>(imgAnimation.export())
|
|
|
|
console.log(height,'height')
|
|
console.log(loading,'loading')
|
|
|
|
useEffect(() => {
|
|
if (!isError && props.fit) {
|
|
Taro.getImageInfo({
|
|
src,
|
|
success() {
|
|
setHeight(undefined)
|
|
}
|
|
})
|
|
}
|
|
setIsError(!src)
|
|
setLoading(!!src)
|
|
}, [src])
|
|
|
|
|
|
useEffect(() => {
|
|
if (props.errorImage) {
|
|
setErrorUrl(props.errorImage)
|
|
return
|
|
}
|
|
switch (props.errorType) {
|
|
case undefined:
|
|
case "acquiesce":
|
|
setErrorUrl(fallback)
|
|
break
|
|
case "avatar":
|
|
setErrorUrl(avatar)
|
|
break
|
|
case 'health':
|
|
setErrorUrl(healthShard)
|
|
break
|
|
case 'profession':
|
|
setErrorUrl(professionShard)
|
|
break
|
|
case 'brand':
|
|
setErrorUrl(brandSecond)
|
|
break
|
|
case 'course':
|
|
setErrorUrl(courseShard)
|
|
break
|
|
}
|
|
}, [props.errorType])
|
|
|
|
// 图片加载失败
|
|
function onErrorHandler() {
|
|
setLoading(false)
|
|
setIsError(true)
|
|
}
|
|
|
|
function onLoadHandler() {
|
|
setLoading(false)
|
|
setIsError(false)
|
|
imgAnimation.opacity(1).step({duration: 200})
|
|
setAnimationData(imgAnimation.export())
|
|
}
|
|
|
|
return (
|
|
<View className={props?.className}
|
|
style={{
|
|
overflow: 'hidden',
|
|
width: width ? typeof width === 'string' ? width : `${width}rpx` : "100%",
|
|
height: height ? typeof height === 'string' ? height : `${height}rpx` : "100%",
|
|
backgroundColor: (isError || !loading) ? 'transparent' : '#F8F8F8',
|
|
}}>
|
|
|
|
{ loading &&
|
|
<View style={{width: "100%", height: '100%',display:'flex',justifyContent:'center',alignItems:'center'}}>
|
|
<Image
|
|
src={logo}
|
|
mode={"widthFix"}
|
|
style={{width: `100rpx`}}/>
|
|
</View>
|
|
}
|
|
{!isError &&
|
|
<View animation={animationData} style={{height: '100%', width: '100%'}}>
|
|
<Image
|
|
{...props}
|
|
src={src}
|
|
mode={mode}
|
|
lazyLoad
|
|
fadeIn
|
|
defaultSource={errorUrl}
|
|
style={{
|
|
width: width ? `${width}rpx` : "100%",
|
|
height: height ? `${height}rpx` : "100%",
|
|
verticalAlign: 'middle'
|
|
}}
|
|
onError={onErrorHandler}
|
|
onLoad={onLoadHandler}/>
|
|
</View>
|
|
}
|
|
{
|
|
isError && !loading &&
|
|
<Image
|
|
mode='aspectFill'
|
|
src={errorUrl}
|
|
lazyLoad
|
|
fadeIn
|
|
style={{width: "100%", height: '100%'}}/>
|
|
}
|
|
</View>
|
|
)
|
|
}
|
|
|
|
export default Img
|
|
|