import React, { useEffect, useRef } from "react";
// 生成带颜色的 SVG 占位图(避免使用外部图片服务)
const getPlaceholderUrl = (i: number) => {
const colors = ["#e3f2fd", "#f3e5f5", "#e8f5e9", "#fff3e0", "#fce4ec", "#e0f7fa"];
const c = colors[i % colors.length];
const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='400' height='250' style='background:${c}'><text x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-family='sans-serif' font-size='18' fill='#999'>Loading...</text></svg>`;
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
};
const getRealImageUrl = (i: number) => {
const colors = ["#1a237e", "#4a148c", "#1b5e20", "#e65100", "#880e4f", "#006064"];
const labels = ["深蓝图片", "深紫图片", "深绿图片", "深橙图片", "深粉图片", "深青图片"];
const c = colors[i % colors.length];
const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='400' height='250' style='background:${c}'><text x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-family='sans-serif' font-size='18' fill='white'>✅ ${labels[i % labels.length]} #${i + 1} 已加载</text></svg>`;
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
};
const LazyImage = ({ index }: { index: number }) => {
const imgRef = useRef<HTMLImageElement>(null);
useEffect(() => {
const img = imgRef.current;
if (!img) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
// 模拟 300ms 网络延迟后加载真实图片
setTimeout(() => {
img.src = getRealImageUrl(index);
}, 300);
observer.unobserve(img);
}
},
{ rootMargin: "0px 0px 100px 0px" }
);
observer.observe(img);
return () => observer.disconnect();
}, [index]);
return (
<div style={{ marginBottom: "12px" }}>
<img
ref={imgRef}
src={getPlaceholderUrl(index)}
alt={`图片 ${index + 1}`}
style={{ width: "100%", height: "120px", objectFit: "cover", borderRadius: "6px", display: "block", transition: "opacity 0.3s" }}
/>
<p style={{ margin: "4px 0 0", fontSize: "12px", color: "#999" }}>图片 #{index + 1}(向下滚动触发加载)</p>
</div>
);
};
export default () => (
<div style={{ height: "320px", overflowY: "auto", border: "1px solid #eee", borderRadius: "8px", padding: "12px" }}>
<p style={{ color: "#666", fontSize: "13px", margin: "0 0 12px" }}>向下滚动列表,观察图片从占位图变为"真实图片"的时机</p>
{Array.from({ length: 10 }).map((_, i) => (
<LazyImage key={i} index={i} />
))}
</div>
);