基于Express+React实现书籍封面随显示尺寸自适应调整(不裁剪)
书籍封面自适应显示问题(MUI实现)
我正在开发一个书籍阅读网站,首页需要展示多本书籍,希望实现书籍封面根据显示尺寸自适应调整大小且不被裁剪,当前使用MUI库构建UI,但不同尺寸的封面会互相挤占空间,当前效果显示封面布局混乱,元素互相挤压。
相关代码
Home.js
import { ImageList, ImageListItem, ImageListItemBar, Typography, Link, Grid, Divider } from '@mui/material' import { useContext } from 'react' import { useNavigate } from 'react-router-dom' import { PageLayout, Context } from '../Components/PageLayout' function Feed({ catg, catgTitle, routeName = "" }) { const navg = useNavigate(); const bookCatg = useContext(Context)[0][catg]; return ( <> <Grid container direction="row" justifyContent="space-between" alignItems="center" > <Grid item> <Typography variant="h6">{catgTitle}</Typography> </Grid> <Grid item> <Link href={`/book/${routeName}`} variant="body1" underline="none" component="button" > More.. </Link> </Grid> </Grid> <Divider /> <ImageList sx={{ pt: '10px' }} cols={4} spacing={1} rowHeight={250} > {bookCatg.map((book) => ( <ImageListItem key={book._id}> <img onClick={() => navg(`/book/${book._id}`)} src={book.img} sx={{ height: "50px" }} alt='Not Found' loading="lazy" /> <ImageListItemBar onClick={() => navg(`/book/${book._id}`)} sx={{ width: '10vw' }} title={book.title} position="below" /> </ImageListItem> ))} </ImageList> </> ) } export default function Home(){ var element = <> <Feed catgTitle={'New Arrival'} catg={'newArrival'} routeName={'newest'} /> <Feed catgTitle={'Popular Books'} catg={'popRating'} routeName={'popular'} /> <Feed catgTitle={'Hot Rated'} catg={'hotRating'} routeName={'hot'} /> <Feed catgTitle={'Rank'} catg={'ranking'} routeName={'ranking'} /> </>; return ( <PageLayout url="/book" gridElem={element} failureMsg="Error" /> ) }
PageLayout.jsx
import { Grid, Typography } from '@mui/material' import { useState, useEffect, createContext } from 'react' import axios from 'axios' import Navbar from './Navbar' import AppFormNav from './AppFormNav' import Loading from './Loading' export const Context = createContext({}); export function PageLayout({ url, nav='normal', elem, gridElem, failureMsg }){ const NavType = { 'normal': <Navbar />, 'form': <AppFormNav /> }; const [info, setInfo] = useState({}); const fetchData = async() => { axios.get(url) .then((resp) => { if(resp.status === 200) setInfo({status: 200, data: resp.data.data}); else if(resp.status === 204) setInfo({ status: 204, data: resp.message }); }) .catch((err) => { setInfo({ status: 400, data: err.response.data.data }) // console.log("Bad Request", err.resp.status); }) }; useEffect(() => { fetchData(); }, []); var gridElement = <Loading />, element, message; if(info.status === 200){ gridElement = gridElem; element = elem; } else if (info.status === 204){ gridElement=<></>; message = failureMsg ? failureMsg : info.data; } return ( <Context.Provider value={info?.data}> <Grid container sx={{ justifyContent: 'center' }}> <Grid item> { NavType[nav] } </Grid> <Grid item xs={12}> { element } </Grid> <Grid item xs={10}> <Typography sx={{ justifyContent: "center", alignItems: "center" }}> {message} </Typography> </Grid> <Grid item xs={ 10 }> { gridElement } </Grid> </Grid> </Context.Provider> ) }
问题原因及解决方法
问题根源
- 图片设置了固定高度
height: "50px",无法自适应容器 ImageList使用固定rowHeight={250}和固定列数cols={4},响应性差ImageListItemBar设置了固定宽度width: '10vw',导致标题容器和图片容器尺寸不匹配,挤占空间
修改方案
- 优化ImageList配置:使用响应式列数,同时设置
rowHeight='auto'让高度自适应内容 - 图片样式调整:设置
objectFit: 'contain'保证图片完整不裁剪,同时让图片占满容器宽度和高度 - 移除固定尺寸限制:去掉ImageListItemBar的固定宽度,让它自适应父容器
修改后的Feed组件关键代码
<ImageList sx={{ pt: '10px' }} // 响应式列数:移动端2列,平板3列,桌面4列 cols={{ xs: 2, sm: 3, md: 4 }} spacing={2} rowHeight="auto" > {bookCatg.map((book) => ( <ImageListItem key={book._id} sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}> <img onClick={() => navg(`/book/${book._id}`)} src={book.img} sx={{ width: '100%', height: 'auto', maxHeight: 200, // 可选:限制图片最大高度保持布局一致 objectFit: 'contain', cursor: 'pointer' }} alt='Not Found' loading="lazy" /> <ImageListItemBar onClick={() => navg(`/book/${book._id}`)} title={book.title} position="below" sx={{ width: '100%', textAlign: 'center', cursor: 'pointer' }} /> </ImageListItem> ))} </ImageList>
说明
objectFit: 'contain'会让图片保持原始比例,完整显示在容器内,不会被裁剪- 响应式列数
cols={{ xs:2, sm:3, md:4 }}确保在不同屏幕尺寸下都有合适的布局 rowHeight="auto"让每个列表项的高度根据图片和标题自动调整,避免固定高度导致的空间浪费或挤压
内容的提问来源于stack exchange,提问作者Fallen
相关产品推荐
相关产品推荐

