React — Grid 栅格布局, 两行代码实现响应式

Grid 栅格布局; 用户端商品列表页面的最佳实践方案,两行代码实现响应式

预览图

image.png

Grid 栅格布局

不建议直接使用grid,使用UI框架的更方便一点,如果非要自己写,也不建议写css,而是使用Grid的库。下面使用AntD和Materrial实现。

Ant Desing 实现

const TestCards: React.FC = ({ children }) => {
  const modifyChildren = useCallback(
    (child: any) => {
      return <Col xs={24} sm={12} lg={6} xl={4}>
        {child}
      </Col>
    }
    , [])
  return <Row gutter={[24, 24]}>
    {React.Children.map(children, modifyChildren)}
  </Row>
}
复制代码

Row 默认是允许展开的,可以当作grid使用;
gutter数组,对应的是行列的间距,可以调节的。

Col 有 xs、sm、md、lg、xl、xxl 可以指定对应的要显示的空间,空间以24作为满的,也就是只有一个Item,12就是显示两个Item;6就是4个Item (24 / 6)。

Col 大小
xs < 576px
sm ≥ 576px
md ≥ 768px
lg ≥ 992px
xl ≥ 1200px
xxl ≥ 1600px

在 CodePen 中打开

Material UI 实现

这个实现多加了一个骨架屏

export const ProductCards = ({
  children,
  isLoading,
  skeletonsCount = 5,
}: IProductCardsProps) => {
  const classes = useProductCardsStyles();

  const modifyChildren = useCallback(
    (child: any) => {
      return (
        <Grid item xs={12} sm={6} lg={4} xl={3} className={classes.col}>
          {child}
        </Grid>
      );
    },
    [classes.col],
  );

  const renderedSkeletons = Array(skeletonsCount)
    .fill(0)
    .map((_, i) => <ProductCardSkeleton key={uid(i)} />);

  return (
    <Grid container className={classes.row}>
      {React.Children.map(isLoading ? renderedSkeletons : children, child =>
        modifyChildren(child),
      )}
    </Grid>
  );
};
复制代码

这里是以12作为基准的,12就是只有一个Item的意思,6就是两个并排的意思,以此类推。

关于响应式尺寸,和antd都是一样的

Grid 大小
xs < 576px
sm ≥ 576px
md ≥ 768px
lg ≥ 992px
xl ≥ 1200px
xxl ≥ 1600px

关于间隔,我们可以修改默认样式实现。下面展示样式示例

import { makeStyles, Theme } from '@material-ui/core';
import { getPercentage } from 'modules/common/utils/styleUtils';

export const useProductCardsStyles = makeStyles<Theme>(theme => ({
  row: {
    marginLeft: theme.spacing(-2),
    marginRight: theme.spacing(-2),
    marginTop: theme.spacing(-4),
    width: 'auto',

    [theme.breakpoints.up('HD')]: {
      marginLeft: theme.spacing(-1.25),
      marginRight: theme.spacing(-1.25),
      marginTop: theme.spacing(-2.5),
    },

    [theme.breakpoints.up('WXGAPlus')]: {
      marginLeft: theme.spacing(-2),
      marginRight: theme.spacing(-2),
      marginTop: theme.spacing(-4),
    },
  },

  col: {
    paddingLeft: theme.spacing(2),
    paddingRight: theme.spacing(2),
    marginTop: theme.spacing(4),

    [theme.breakpoints.up('HD')]: {
      flex: '0 0 auto',
      width: getPercentage(1, 5),
      paddingLeft: theme.spacing(1.25),
      paddingRight: theme.spacing(1.25),
      marginTop: theme.spacing(2.5),
    },

    [theme.breakpoints.up('WXGAPlus')]: {
      paddingLeft: theme.spacing(2),
      paddingRight: theme.spacing(2),
      marginTop: theme.spacing(4),
    },
  },
}));

复制代码

内容填充

一般栅格布局展示的内容都要有一个图片,我们给他加一个吧。

<Container>
    <TestCards>
      {list.map((item) => <TestCard key={item} index={item} />)}
    </TestCards>
</Container>
复制代码

这是列表的渲染,上面符合需求的栅格布局组件已经做好了,下面只需要循环列表渲染即可,那我们简单加一个item的组件吧,就叫TestCard吧。

const TestCard: React.FC<{ index: number }> = ({ index }) => {
  return <Card>
    <div style={styles.cardRoot}>
      <div style={styles.mainImgBox}>
        <img src={imgUrl} alt="" style={styles.mainImg} />
      </div>
      Col{index}
    </div>
  </Card>
}
复制代码

说一下哈,之所以img外面要包一层,是因为这个可以防止坍塌也可以固定大小,img就以Box的大小为自己大小,然后内部使用objectFit控制图片展示方式。

样式示例

const styles: { [className: string]: React.CSSProperties } = {
  cardRoot: { width: '100%', height: '100%' },
  mainImgBox: { paddingTop: '100%', position: 'relative' },
  mainImg: { position: 'absolute', top: 0, left: 0, objectFit: 'contain', width: '100%', height: '100%' },
}
复制代码

有没有注意到一点,img从始至终都没有定义过自己的大小。这样就可以和grid完美配合啦。

当然这个只是简陋示例,具体img要做一些错误,清晰度等处理。

Code And Preview

在 CodePen 中打开

— 完 —

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享