
用React打造炫酷的随机图片展示墙(接上篇API教程)
你好,我是Sakuraseven。在上一篇教程中,我们搭建了随机图片API。今天我们来让这个API真正"活"起来——用React构建一个动态图片展示墙!最终效果如下:
[此处可放GIF演示图或截图]
你将学到:
✅ React基础组件设计
✅ 异步请求API数据
✅ 响应式图片布局
✅ 无限滚动加载
✅ 添加加载动画
一、项目初始化
使用Create React App快速搭建环境:
npx create-react-app image-wall
cd image-wall
npm start
二、核心组件设计
文件结构
src/
├── components/
│ ├── ImageCard.js # 单张图片卡片
│ └── ImageWall.js # 图片墙主组件
├── App.js
└── index.js
1. 图片卡片组件 (ImageCard.js
)
import React from 'react';
const ImageCard = ({ imgUrl, altText }) => {
return (
<div className="image-card">
<img
src={imgUrl}
alt={altText || '随机图片'}
loading="lazy" // 原生懒加载
/>
</div>
);
};
export default ImageCard;
2. 图片墙主组件 (ImageWall.js
)
import React, { useState, useEffect } from 'react';
import ImageCard from './ImageCard';
const ImageWall = () => {
const [images, setImages] = useState([]);
const [loading, setLoading] = useState(true);
// 初始加载图片
useEffect(() => {
fetchImages(10); // 首次加载10张
}, []);
// 调用API函数
const fetchImages = async (count = 5) => {
setLoading(true);
const baseUrl = 'http://your-api.com/random-img'; // 替换为你的API地址
try {
// 并行请求多张图片
const requests = Array(count).fill().map(() => fetch(baseUrl));
const responses = await Promise.all(requests);
const newImages = await Promise.all(
responses.map(res => res.url) // 获取图片URL
);
setImages(prev => [...prev, ...newImages]);
} catch (error) {
console.error('加载图片失败:', error);
} finally {
setLoading(false);
}
};
// 无限滚动处理
useEffect(() => {
const handleScroll = () => {
if (
window.innerHeight + document.documentElement.scrollTop >=
document.documentElement.offsetHeight - 500
) {
!loading && fetchImages(5); // 每次滚动加载5张
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [loading]);
return (
<div className="image-wall">
<div className="grid-container">
{images.map((imgUrl, index) => (
<ImageCard key={`${imgUrl}-${index}`} imgUrl={imgUrl} />
))}
</div>
{loading && <div className="loader">加载中...</div>}
</div>
);
};
export default ImageWall;
三、关键功能实现技巧
1. 响应式网格布局(纯CSS实现)
/* src/App.css */
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
padding: 20px;
}
.image-card img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
transition: transform 0.3s ease;
}
.image-card img:hover {
transform: scale(1.03);
}
2. 优雅的加载状态
// 在ImageWall组件中添加
{loading && (
<div className="loader-container">
<div className="spinner"></div>
<p>正在加载更多美图...</p>
</div>
)}
/* 加载动画CSS */
.loader-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(0, 0, 0, 0.1);
border-left-color: #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
3. 图片懒加载优化
// 在ImageCard组件中使用Intersection Observer
import React, { useRef, useState, useEffect } from 'react';
const ImageCard = ({ imgUrl }) => {
const imgRef = useRef();
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.unobserve(imgRef.current);
}
}, { threshold: 0.1 });
observer.observe(imgRef.current);
return () => observer.disconnect();
}, []);
return (
<div ref={imgRef} className="image-card">
{isVisible ? (
<img src={imgUrl} alt="随机图片" />
) : (
<div className="placeholder" /> // 占位元素
)}
</div>
);
};
四、部署到线上(Vercel实战)
安装Vercel CLI
npm install -g vercel
项目根目录登录
vercel login
一键部署
vercel
五、性能优化建议
CDN加速:将图片上传至云存储(如AWS S3+CloudFront)
API缓存:设置更长的Cache-Control头部
代码分割:React.lazy动态导入组件
图片格式:API支持返回WebP格式(需修改后端)
遇到问题怎么办?
Q:图片加载出现跨域错误?
A:在API端设置响应头:
resp.headers['Access-Control-Allow-Origin'] = '*' # 生产环境应指定域名
Q:布局出现错位?
A:确保所有图片比例统一,或使用CSS的aspect-ratio
属性
下一篇预告:
《给随机图片API加上AI鉴黄功能:保护你的网站安全》
我们将使用TensorFlow.js在前端实时检测图片内容安全!
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 Sakuraseven!
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果