refactor(PostCard, ImageGrid, SmartImage): enhance post editing display and image handling
- Introduced a new method to determine the last edited time for posts, prioritizing content_edited_at for better accuracy in display. - Updated PostCard and PostDetailScreen components to utilize the new editing display logic. - Enhanced ImageGrid and SmartImage components to support additional preview URLs and improve image loading behavior, including lazy loading optimizations for web. - Modified Post and PostDTO interfaces to include contentEditedAt for better tracking of post edits.
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
ActivityIndicator,
|
||||
Pressable,
|
||||
StyleProp,
|
||||
Platform,
|
||||
} from 'react-native';
|
||||
import { Image as ExpoImage } from 'expo-image';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
@@ -61,6 +62,8 @@ export interface SmartImageProps {
|
||||
usePreview?: boolean;
|
||||
/** 是否懒加载 */
|
||||
lazyLoad?: boolean;
|
||||
/** Web 端 IntersectionObserver rootMargin,略提前加载进入视口附近的图 */
|
||||
lazyRootMargin?: string;
|
||||
/** 缓存策略 */
|
||||
cachePolicy?: 'memory' | 'disk' | 'memory-disk' | 'none';
|
||||
}
|
||||
@@ -85,11 +88,13 @@ export const SmartImage: React.FC<SmartImageProps> = ({
|
||||
previewUrl,
|
||||
usePreview = false,
|
||||
lazyLoad = false,
|
||||
lazyRootMargin = '160px',
|
||||
cachePolicy = 'memory-disk',
|
||||
}) => {
|
||||
const [loadState, setLoadState] = useState<ImageLoadState>('loading');
|
||||
const [isVisible, setIsVisible] = useState(!lazyLoad);
|
||||
const [isVisible, setIsVisible] = useState(() => !lazyLoad || Platform.OS !== 'web');
|
||||
const [shouldLoadOriginal, setShouldLoadOriginal] = useState(false);
|
||||
const lazyTargetRef = useRef<View>(null);
|
||||
|
||||
// 解析图片源 - 支持 uri 或 url 字段
|
||||
const imageUri = typeof source === 'string'
|
||||
@@ -99,6 +104,39 @@ export const SmartImage: React.FC<SmartImageProps> = ({
|
||||
// 解析预览图 URL
|
||||
const previewUri = typeof previewUrl === 'string' ? previewUrl : '';
|
||||
|
||||
useEffect(() => {
|
||||
setShouldLoadOriginal(false);
|
||||
setLoadState('loading');
|
||||
}, [imageUri]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!lazyLoad) {
|
||||
setIsVisible(true);
|
||||
return;
|
||||
}
|
||||
if (Platform.OS !== 'web') {
|
||||
setIsVisible(true);
|
||||
return;
|
||||
}
|
||||
setIsVisible(false);
|
||||
const node = lazyTargetRef.current as unknown as Element | null;
|
||||
if (!node || typeof IntersectionObserver === 'undefined') {
|
||||
setIsVisible(true);
|
||||
return;
|
||||
}
|
||||
const observer = new IntersectionObserver(
|
||||
entries => {
|
||||
if (entries.some(e => e.isIntersecting)) {
|
||||
setIsVisible(true);
|
||||
observer.disconnect();
|
||||
}
|
||||
},
|
||||
{ rootMargin: lazyRootMargin }
|
||||
);
|
||||
observer.observe(node);
|
||||
return () => observer.disconnect();
|
||||
}, [lazyLoad, lazyRootMargin, imageUri]);
|
||||
|
||||
// 智能选择图片 URL
|
||||
const getImageUrl = useCallback((): string => {
|
||||
// 如果应该加载原图(预览图已加载完成或没有预览图)
|
||||
@@ -200,10 +238,12 @@ export const SmartImage: React.FC<SmartImageProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
// 如果是懒加载且不可见,显示占位
|
||||
// 如果是懒加载且不可见,显示占位(Web 上由 IntersectionObserver 驱动进入视口后再加载)
|
||||
if (lazyLoad && !isVisible) {
|
||||
return (
|
||||
<View
|
||||
ref={Platform.OS === 'web' ? lazyTargetRef : undefined}
|
||||
collapsable={false}
|
||||
style={[containerStyle, style as ViewStyle, { backgroundColor: '#F5F5F5' }]}
|
||||
testID={testID}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user