Browse Source

首页骨架屏

main
Your Name 3 weeks ago
parent
commit
8413b9dfa0
  1. 98
      app/screens/HomeScreen.tsx

98
app/screens/HomeScreen.tsx

@ -52,6 +52,61 @@ type CategoryContentType = {
[key: string]: SubcategoryItem[]; [key: string]: SubcategoryItem[];
}; };
// 懒加载图片组件 - 改进版本
const LazyImage = React.memo(
({
uri,
style,
resizeMode,
}: {
uri: string;
style: any;
resizeMode: any;
}) => {
const [isLoaded, setIsLoaded] = useState(false);
const [hasError, setHasError] = useState(false);
const onLoad = useCallback(() => {
setIsLoaded(true);
}, []);
const onError = useCallback(() => {
setHasError(true);
setIsLoaded(true); // Also mark as loaded on error to remove placeholder
}, []);
return (
<View style={[style, { overflow: "hidden" }]}>
{/* Show placeholder while image is loading */}
{!isLoaded && !hasError && (
<View style={[style, styles.imagePlaceholder, { position: 'absolute', zIndex: 1 }]} />
)}
{/* Show error state if image failed to load */}
{hasError && (
<View
style={[style, styles.imagePlaceholder, { position: 'absolute', zIndex: 1 }]}
>
<IconComponent name="image-outline" size={24} color="#999" />
<Text style={{ fontSize: fontSize(12), color: "#999", marginTop: 4 }}>
</Text>
</View>
)}
{/* Actual image */}
<Image
source={{ uri }}
style={[style, { opacity: isLoaded ? 1 : 0 }]}
resizeMode={resizeMode}
onLoad={onLoad}
onError={onError}
/>
</View>
);
}
);
// 产品骨架屏组件 - 用于加载状态 // 产品骨架屏组件 - 用于加载状态
const ProductSkeleton = React.memo(() => { const ProductSkeleton = React.memo(() => {
// 创建动画值 // 创建动画值
@ -303,19 +358,30 @@ export const HomeScreen = () => {
activeOpacity={0.9} activeOpacity={0.9}
style={styles.beautyProductCard1} style={styles.beautyProductCard1}
> >
<ImageBackground <View style={styles.beautyCardContainer1}>
style={styles.beautyCardContainer1} {item.product_image_urls && item.product_image_urls.length > 0 ? (
source={{ uri: item.product_image_urls[0] }} <LazyImage
> uri={item.product_image_urls[0]}
style={styles.productImage}
resizeMode="cover"
/>
) : (
<View style={[styles.productImage, styles.imagePlaceholder]}>
<IconComponent name="image-outline" size={24} color="#999" />
</View>
)}
{userStore.user?.user_id && ( {userStore.user?.user_id && (
<View style={styles.vipButtonContainer}>
<TouchableOpacity style={styles.vipButton}> <TouchableOpacity style={styles.vipButton}>
<Text style={styles.vipButtonText}>VIP</Text> <Text style={styles.vipButtonText}>VIP</Text>
<Text style={styles.vipLabelBold}> <Text style={styles.vipLabelBold}>
{userStore.user?.vip_level} {userStore.user?.vip_level}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View>
)} )}
</ImageBackground> </View>
<View style={styles.beautyProductCard}> <View style={styles.beautyProductCard}>
<Text <Text
style={styles.beautyProductTitle} style={styles.beautyProductTitle}
@ -921,10 +987,17 @@ const styles = StyleSheet.create({
alignItems: "flex-end", alignItems: "flex-end",
justifyContent: "center", justifyContent: "center",
width: "100%", width: "100%",
paddingBottom: 160, height: 160,
backgroundColor: "transparent", backgroundColor: "transparent",
borderRadius: 10, borderRadius: 10,
overflow: "hidden", overflow: "hidden",
position: "relative",
},
vipButtonContainer: {
position: "absolute",
top: 0,
right: 0,
zIndex: 2,
}, },
vipButton: { vipButton: {
width: widthUtils(30, 66).width, width: widthUtils(30, 66).width,
@ -1059,5 +1132,16 @@ const styles = StyleSheet.create({
position: 'absolute', position: 'absolute',
top: 0, top: 0,
left: 0, left: 0,
} },
imagePlaceholder: {
backgroundColor: '#EAEAEA',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 8,
},
productImage: {
width: "100%",
height: "100%",
borderRadius: 10,
},
}); });
Loading…
Cancel
Save