背景
为什么要自己手写antd的Row组件和Col组件呢?
很简单,就是因为设计稿要求表单内一行五个FormItem,并且这几个FormItem随着屏幕尺寸自适应。但是antd的栅格化系统是按照24等分来的,最关键的是antd中的Col组件的span不支持小数,而需求的一行5个,24/5 = 4.8,是不支持的,所以只能自己手写了
实现这个需求实际上有两个方式
- 不封装纯css实现
- 封装组件
这里主要表现的是第二种封装组件的形式
实现思路
手写MyRow
和MyCol
MyRow
组件接收gutter
和children
作为props。gutter
用于定义列与列之间的间隔,children
则是要渲染在行内的内容。
MyCol
组件接收decimalSpan
, children
, gutter
, flex
, style
, 和 className
作为props:
decimalSpan
是一个可选的数字,表示占用的网格列数的百分比(相对于24列的总宽度)。如果提供,它将计算为占总宽度的百分比,并用于设置列的宽度。gutter
定义了列之间的间隔。flex
是一个可选的属性,用于设置列的弹性布局。如果是数字,将会被转换成百分比形式的flex值;如果是字符串,则直接使用。style
是一个可选的CSS属性对象,可以覆盖或添加自定义样式。className
是一个可选的字符串,用于应用CSS类。
实现方式
MyRow
只是简单地将props传递给Ant Design的Row
组件。
MyCol
则更加复杂一些,它首先计算spanWidth
的值,如果decimalSpan
被提供,spanWidth
将是列宽度的百分比;否则,它是0。然后,如果flex
被提供,会创建一个flexStyle
对象,其中包含适当的flex属性。这些样式(包括从style
prop传入的任何附加样式)都会被应用到一个div
元素上,而不是Ant Design的Col
。
下面就是整个组件的代码,ts+hook
typescript
import { Row } from 'antd';
import React from 'react';
import type { Gutter } from 'antd/es/grid/row';
export const MyRow = ({
gutter,
children,
}: {
gutter: Gutter | [Gutter, Gutter];
children: React.ReactNode;
}) => <Row gutter={gutter}>{children}</Row>;
export const MyCol = ({
decimalSpan,
children,
gutter,
flex,
style ={},
className,
}: {
decimalSpan?: number;
children: React.ReactNode;
gutter: number
flex?: number | string;
style?:React.CSSProperties
className?:string
}) => {
// 如果提供了span属性,计算宽度的百分比
const spanWidth = decimalSpan ? `${(decimalSpan / 24) * 100}%` : 0;
// 如果提供了flex属性,根据flex值设置弹性布局
const flexStyle = flex ? { flex: typeof flex === 'number' ? `0 0 ${flex}%` : flex } : {};
const colStyle = {
paddingLeft: gutter / 2,
paddingRight: gutter / 2,
width: spanWidth, // 如果flex属性存在,spanWidth将会被flex样式覆盖
...flexStyle,
...style,
};
return <div className={className} style={colStyle}>{children}</div>;
};