文章目录
- Ant Design Card 组件展示图片
- 理解card组件结构
- 隐藏卡片内容区域
- 下拉时加载图片卡片
- 加载更多
- 代码
- 分页的方式加载图片列表【推荐】
- 实现思路
- 代码demo
- 缩略图
- 在card组件下发显示图片文件名
- 卡片操作
- 分页
Ant Design Card 组件展示图片
官方文档:
Card卡片组件 https://4x.ant.design/components/card-cn/#Card
ProCard高级卡片 https://procomponents.ant.design/components/card
Card卡片
通用卡片容器。
何时使用#
最基础的卡片容器,可承载文字、列表、图片、段落,常用于后台概览页面。
理解card组件结构
如上图,Card组件分成如上组成部分,
- header这部分 是,title属性来配置
- 卡片封面 是sove属性来配置
- 卡片内容区域 Card.Meta 来配置
- 卡片动作部分,是action属性来配置
隐藏卡片内容区域
我们使用一个名为 custom-card 的类名来设置卡片容器的样式,并通过 bodyStyle 属性将内容区域的样式设置为 display: none,完全隐藏内容区域。
下拉时加载图片卡片
需求是展示支持分页的图片,并且希望在下拉时加载新的图片卡片,可以使用 Ant Design 的 List 组件和滚动事件来实现。
容器的高度自适应,并且卡片在宽度不足时自动换行显示,可以使用 CSS 中的 Flexbox 布局来实现
return (<div style={{ display: 'flex', flexWrap: 'wrap' }} onScroll={handleScroll}><Listgrid={{ gutter: 16, column: 4 }}dataSource={data}loading={loading}loadMore={loading ? <Spin /> : undefined}renderItem={(item) => (<List.Item style={{ flexBasis: '25%' }}><Card cover={<img alt="Example Image" src={item} />} /></List.Item>)}/></div>);
我们将容器的样式设置为 display: ‘flex’,并使用 flexWrap: ‘wrap’ 让卡片在宽度不足时自动换行显示。
将卡片项的样式设置为 flexBasis: ‘20%’,这样每个卡片项将占据容器宽度的 20%。通过将 column 属性设置为 5,我们让 List 组件一行显示 5 个卡片。
加载更多
将List组件的 loadMore 属性的值设置为一个函数,用于触发加载更多数据的操作。
将 handleLoadMore 定义为一个函数,用于触发加载更多数据的操作。如果正在加载中,将 handleLoadMore 设置为空函数;否则,将其设置为 fetchData 函数,以触发加载更多数据。
通过这个修改,当滚动到底部时,将触发加载更多数据的操作,并通过模拟异步加载数据的方式展示加载更多的效果。
代码
import { List, Card, Spin } from 'antd';
import { useEffect, useState } from 'react';const ImageList: React.FC = () => {const [loading, setLoading] = useState(false);const [data, setData] = useState<string[]>([]);const fetchData = () => {setLoading(true);// 模拟异步加载数据setTimeout(() => {const newData = Array.from({ length: 10 }, (_, index) => `https://via.placeholder.com/300?text=Image${index + 1}`);setData((prevData) => [...prevData, ...newData]);setLoading(false);}, 1000);};useEffect(() => {fetchData();}, []);const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {const { scrollTop, clientHeight, scrollHeight } = e.currentTarget;const isAtBottom = scrollTop + clientHeight === scrollHeight;if (isAtBottom && !loading) {fetchData();}};const handleLoadMore = loading ? () => {} : null;return (<div style={{ display: 'flex', flexWrap: 'wrap' }} onScroll={handleScroll}><Listgrid={{ gutter: 16, column: 5 }}dataSource={data}loading={loading}loadMore={handleLoadMore}renderItem={(item) => (<List.Item style={{ flexBasis: '20%' }}><Card cover={<img alt="Example Image" src={item} />} /></List.Item>)}/></div>);
};export default ImageList;
分页的方式加载图片列表【推荐】
使用分页的方式可以更加可控地展示数据,并提供更好的用户体验。通过显示当前页数、总页数以及提供页码切换的功能,用户可以清楚地知道当前所处的页面位置,并且可以自由地在不同页面之间进行切换。
实现思路
我更喜欢使用分页而不是加载更多的方式来展示数据,您可以结合 Ant Design 的 Pagination 组件来实现分页效果
代码demo
import { List, Card, Pagination } from 'antd';
import { useEffect, useState } from 'react';const ImageList: React.FC = () => {const [loading, setLoading] = useState(false);const [data, setData] = useState<string[]>([]);const [page, setPage] = useState(1);const pageSize = 12; // 每页显示的图片数量const fetchData = () => {setLoading(true);// 模拟异步加载数据setTimeout(() => {const newData = Array.from({ length: pageSize }, (_, index) => `https://via.placeholder.com/300?text=Image${(page - 1) * pageSize + index + 1}`);setData(newData);setLoading(false);}, 1000);};useEffect(() => {fetchData();}, [page]);const handlePageChange = (pageNumber: number) => {setPage(pageNumber);};return (<div><Listgrid={{ gutter: 16, column: 4 }}dataSource={data}loading={loading}renderItem={(item) => (<List.Item><Card cover={<img alt="Example Image" src={item} />} /></List.Item>)}/><Pagination current={page} pageSize={pageSize} total={100} onChange={handlePageChange} /></div>);
};export default ImageList;
缩略图
import { List, Card, Pagination } from 'antd';
import axios from 'axios';
import { useEffect, useState } from 'react';const ImageList: React.FC = () => {const [loading, setLoading] = useState(false);const [data, setData] = useState<string[]>([]);const [page, setPage] = useState(1);const pageSize = 12; // 每页显示的图片数量const fetchData = async () => {setLoading(true);try {let token = localStorage.getItem('token');if (null === token) {token = '';}const response = await axios.get('/api/v1/imageManage/listThumbImages', {params: {page: page,pageSize: pageSize,},headers: {Authorization: `Bearer ${token}`, // 替换为您的 Bearer Token},});console.log("listThumbImages response data: ", response.data)//前端只通过 Base64 字符串无法确定图片的格式。Base64 只是一种表示图像数据的编码方式,并不能直接指示图像的格式。//在前端展示 Base64 图片时,通常需要提供图像的 MIME 类型来指示图像的格式。MIME 类型是一种标识数据类型的字符串,例如 "image/jpeg" 表示 JPEG 图像,"image/png" 表示 PNG 图像。// 将图像的 MIME 类型一并返回,这样前端就能够根据提供的 MIME 类型来正确解析和显示图像//根据文件名组装图像的 MIME 类型const updatedData = response.data.map(item => {const fileExtension = item.FileName.split('.').pop().toLowerCase();let imageFormat = "image/jpeg"; // 默认格式为 JPEGif (fileExtension === "png") {imageFormat = "image/png";} else if (fileExtension === "gif") {imageFormat = "image/gif";}return {...item,ImageFormat: imageFormat,};});setData(updatedData);setLoading(false);} catch (error) {console.error('Error fetching thumbnails:', error);setLoading(false);}};useEffect(() => {fetchData();}, [page]);const handlePageChange = (pageNumber: number) => {setPage(pageNumber);};return (<div><Listgrid={{ gutter: 16, column: 6 }}dataSource={data}loading={loading}renderItem={(item: any) => (<List.Item><Cardcover={item.ThumbnailBase64 ? (<img alt="Example Image" src={`data:${item.ImageFormat};base64,${item.ThumbnailBase64}`} />) : (<div>No Thumbnail</div>)}/></List.Item>)}/><Pagination current={page} pageSize={pageSize} total={100} onChange={handlePageChange} /></div>);
};export default ImageList;
代码细节解释:
- 每行显示多个?
<Listgrid={{ gutter: 16, column: 6 }}
grid 属性设置为 { gutter: 16, column: 6 },表示创建一个具有 6 列的网格布局,并且网格项之间的间距为 16 像素。
在 List 组件中,grid 属性用于定义网格布局的样式。它接受一个对象作为参数,该对象包含两个属性:gutter 和 column。
- gutter:用于设置网格项之间的间距。可以将其设置为一个数字来表示像素值,或者设置为一个数组 [水平间距, 垂直间距] 来分别表示水平和垂直方向上的间距。
- column:用于设置网格的列数。可以将其设置为一个数字来表示列数,或者设置为一个数组 [列数, 列宽] 来分别表示列数和列宽。
- 分页?
如下,添加 分页组件Pagination
即可
为 Card 添加预览、下载和删除功能的按钮
通过以上修改,预览、下载和删除的图标会在鼠标悬停在 Card 上时放大并显示。
在上述 CSS 文件中,我们通过设置 .image-actions 类的样式来实现鼠标悬停时的显示效果,并使用 .custom-card:hover .image-actions 选择器来控制悬停时图标的显示。我们还设置了 .icon 类的样式,用于调整图标的大小和颜色。
实现鼠标悬停时图标变色的效果,你可以使用 CSS 的 :hover 伪类选择器来设置图标的样式
.icon-wrapper {display: flex;gap: 10px;}.icon-wrapper .icon {font-size: 24px;color: #000;cursor: pointer;}.icon-wrapper .icon:hover {color: #ff0000; /* 设置图标的悬停颜色 */}
在card组件下发显示图片文件名
Meta官方说明:https://4x.ant.design/components/card-cn/#Card.Meta
要将文件名显示在卡片的底部,您可以在 Card 组件中添加一个位于底部的 Meta 组件,并将文件名作为 Meta 组件的 description 属性。
可以利用 Card.Meta 支持更灵活的内容
卡片操作
官方文档:https://4x.ant.design/components/card-cn/#Card
使用 actions 卡片操作组,位置在卡片底部
分页
分页组件用法:
<Pagination current={page} pageSize={pageSize} total={totalRecords} onChange={handlePageChange} />
分页相关变量
const [page, setPage] = useState(1);const pageSize = 10; // 每页显示的图片数量const [totalRecords, setTotalRecords] = useState(0);
在 fetchData 函数中的成功回调中,使用 setPage 和 setTotalRecords来更新 page 和 totalRecords状态。这样就能确保在获取数据后及时更新这些状态。
获取数据后,设置分页信息变量
// 获取分页信息const pagination = responseData.pagination;console.log("获取分页信息 pagination: ",pagination)setPage(pagination.page);setTotalRecords(pagination.totalItems);
注意:在 Pagination 组件中,total 属性应该是总记录数。前端会根据 total 属性和每页显示的数量自动计算出分页的页数。这样做可以确保在数据更新或动态加载时,分页组件能够正确地显示页码和处理分页逻辑。