使用React-Bootstrap实现Instrument Card动态尺寸且保留最小尺寸方案咨询
解决方案
实现代码
修改InstrumentList组件
替换原有的CardDeck布局为Bootstrap栅格的Container+Row+Col结构,先将乐器数组按每行5个拆分,再逐行渲染:
import InstrumentCard from './InstrumentCard' import styles from '../styles/InstrumentList.module.scss' import { Container, Row, Col } from 'react-bootstrap' // 数组分组工具函数:将一维数组按指定长度拆分为二维数组 const chunkArray = (arr, size) => { const result = [] for (let i = 0; i < arr.length; i += size) { result.push(arr.slice(i, i + size)) } return result } const InstrumentList = ({instruments, onDel, onLoc, onShuf, onRep, onRepButClick, setRepInstrumentID}) => { // 按每行5个拆分乐器列表 const groupedInstruments = chunkArray(instruments, 5) return ( <Container className={styles.container} fluid> {groupedInstruments.map((rowInstruments, rowIndex) => ( <Row key={rowIndex} className="mb-3"> {rowInstruments.map((instrument, colIndex) => ( <Col key={colIndex} className={styles.cardCol} style={{flex: '0 0 20%', maxWidth: '20%', padding: '0.5rem'}} > <InstrumentCard id={rowIndex * 5 + colIndex} instr={instrument} name={instrument.name} description={instrument.description} imagePath={instrument.image} wikiLink={instrument.wikipedia} tubeLink={instrument.youtube} onDelete={onDel} isLocked={instrument.locked} onLock={onLoc} onShuffle={onShuf} onReplace={onRep} onRepButtonClick={onRepButClick} setReplacementInstrumentID={setRepInstrumentID} /> </Col> ))} </Row> ))} </Container> ) } export default InstrumentList
修改InstrumentCard组件
移除卡片的flexGrow属性,改为撑满外层Col容器即可:
import {Card, Button, ButtonGroup} from 'react-bootstrap' import styles from '../styles/InstrumentCard.module.scss' const InstrumentCard = ({id, name, description, imagePath, wikiLink, tubeLink, onDelete, isLocked, onLock, onShuffle, setReplacementInstrumentID, onRepButtonClick}) => { return ( <Card style={{ width: '100%', margin: 0, minHeight:'32rem'}}> <div> <button id="lockButton" onClick={() => {onLock(id)}} className={isLocked ? styles.btnOverrideLocked : styles.btnOverride}>{isLocked ? "🔒" : "🔓"}</button> <button id="shuffleButton" autoFocus={true} onClick={()=> {onShuffle(id)}} className={styles.btnOverrideShuffle} style={{float: "right"}}><span>🔀</span></button> </div> <Card.Img variant="top" src={imagePath} style={{padding:'1rem', maxHeight: '10rem', height:'100%', objectFit: 'contain'}} /> <Card.Body style={{display: 'flex', flexDirection: 'column', justifyContent: 'space-between'}}> <div> <Card.Title>{name}</Card.Title> <Card.Text>{description}</Card.Text> </div> <div style={{marginTop: '.5rem'}}> <ButtonGroup style={{width: "100%"}}> <Button variant="danger" onClick={()=> onDelete(id)}>Delete</Button> <Button variant="secondary" onClick={()=> {setReplacementInstrumentID(id); onRepButtonClick()}} >Replace</Button> </ButtonGroup> </div> </Card.Body> <Card.Footer> <Card.Link target="_blank" rel="noopener noreferrer" href={wikiLink}>Wikipedia</Card.Link> <Card.Link target="_blank" rel="noopener noreferrer" href={tubeLink}>Youtube</Card.Link> </Card.Footer> </Card> ) } export default InstrumentCard
可选:响应式适配
如果需要不同屏幕尺寸下每行显示不同数量的卡片,可在InstrumentList.module.scss中添加媒体查询:
// 平板端每行3个 @media (max-width: 992px) { .cardCol { flex: 0 0 33.33% !important; max-width: 33.33% !important; } } // 手机端每行2个 @media (max-width: 768px) { .cardCol { flex: 0 0 50% !important; max-width: 50% !important; } } // 小屏手机每行1个 @media (max-width: 576px) { .cardCol { flex: 0 0 100% !important; max-width: 100% !important; } }
实现原理
- 数组分组:通过chunkArray函数把一维的乐器列表拆分为每5个元素一组的二维数组,保证每行固定渲染5个卡片,避免最后一行元素不足时的布局异常
- 固定宽度控制:每个卡片外层的Col容器固定占行宽的20%(100%/5),所有容器尺寸完全统一,卡片设置
width:100%撑满容器,自然不会出现大小不一的问题 - 移除自动拉伸:去掉卡片的
flexGrow:1属性后,卡片不会自动填充行内剩余空间,最后一行哪怕不足5个卡片,也会和上方卡片保持完全相同的尺寸 - 适配灵活:只需要调整分组的size参数和Col的宽度比例,就能快速修改不同屏幕下每行的卡片数量,完全符合Bootstrap的响应式设计规范
内容的提问来源于stack exchange,提问作者Robby Hoover
相关产品推荐
相关产品推荐

