平台首页有选货市场,商品大图展示时,要求根据浏览器宽度均匀排布。 即浏览器宽度不同,一行展示的商品数量不同,通过改变外边距,让商品均匀填充满容器盒子。
通过css的flex布局和justify-content: space-between让商品元素均匀排布。效果如下: 可见,当商品铺差不多够满了一行时展示效果是ok的,不足一行时,就会有问题。
react代码
const GOODS_CARD_WIDTH = 250; // 每个卡片的固定宽度 const MIN_MARGIN_RIGHT = 14; // 最小的margin-right值 const GOODS_NUM_INLINE = 4; // 一行最少展示的商品数量 class GoodsCardList extends React.Component { // 计算方法 private calcCardMarginRight = () => { // 容器总宽度 const goodsBoxWidth = document.querySelector('.img-goods-box-hyy')?.getBoundingClientRect().width; if (goodsBoxWidth) { // 计算一行最多可放的商品数量 const n = parseInt(String(goodsBoxWidth / (GOODS_CARD_WIDTH + MIN_MARGIN_RIGHT))); // 超过GOODS_NUM_INLINE = 4时,计算新的margin-right值 if (n >= GOODS_NUM_INLINE) { const newMarginRight = parseInt(String((goodsBoxWidth - (GOODS_CARD_WIDTH * n)) / (n - 1))); // console.log('每行展示的商品数量', n); // console.log('每个商品的右边距', newMarginRight); this.setState({ cardMarginRight: (newMarginRight <= MIN_MARGIN_RIGHT) ? MIN_MARGIN_RIGHT : newMarginRight, imgBoxMarginRight: (newMarginRight <= MIN_MARGIN_RIGHT) ? 0 : (0 - newMarginRight) }); } } } componentDidMount() { // 监听窗口大小改变事件,实时计算 window.addEventListener('resize', this.resizeHandler); this.calcCardMarginRight(); } componentWillUnmount() { window.removeEventListener('resize', this.resizeHandler); } render() { return ( <div className="clr img-goods-box-hyy"> <ul className="img-goods-list" style={{marginRight: imgBoxMarginRight + 'px'}}> {goods.length ? goods.map(item => this.renderImg(item)) : <li style={{width: '100%'}}> <Empty /> </li>} {new Array(10).fill(1).map((_, index) => <li key={index} className="img-list-item__empty" />)} </ul> </div> ) } }效果如下:
较宽的屏幕中 屏幕变窄后
调皮的滚动条
按照以上方法,首次计算父容器宽度时,由于数据是异步获取的,滚动条还没出现,按照无滚动条的宽度计算出来的margin-right值大了,所以每行最后一个元素会被迫换行,造成很大的留白。
补救措施:
先计算出滚动条的宽度,初始计算的时候父容器宽度减掉滚动条宽度后再计算margin-right 将上面代码稍作修改即可,这里就不贴了。