前言
筆者目前業務主要圍繞ant design mobile
組件庫來交付H5前端工作。
故此出此專欄來解讀每一個組件是如何實現的。
本文基于AI來解讀Space組件。
文檔鏈接:
https://mobile.ant.design/zh/components/space
源碼:
https://github.com/ant-design/ant-design-mobile/blob/master/src/components/space/space.tsx
設計prompt
解讀antd-mobile space組件,結構化思維輸出整個組件實現流程,按步驟提供關鍵代碼解讀 // 附組件代碼
實現步驟
1. 目的
在子元素間插入可定制間距(horizontal / vertical / wrap / align / justify),通過 CSS 變量暴露 gap(–gap、–gap-horizontal、–gap-vertical)。
2. Props(關鍵)
export type SpaceProps = {direction?: 'horizontal' | 'vertical' // 默認 'horizontal'align?: 'start' | 'end' | 'center' | 'baseline'justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly' | 'stretch'wrap?: booleanblock?: booleanonClick?: (e: React.MouseEvent<HTMLDivElement>) => voidchildren?: React.ReactNode
} & NativeProps<'--gap' | '--gap-vertical' | '--gap-horizontal'>
默認:
const defaultProps = { direction: 'horizontal' }
3. 渲染邏輯(核心 JSX)
- 合并默認 props(mergeProps)
- 使用 withNativeProps 注入原生屬性(style/className/data-*)
- 每個子節點包裹為
.adm-space-item
(過濾 null/undefined)
關鍵代碼:
export const Space: FC<SpaceProps> = p => {const props = mergeProps(defaultProps, p)const { direction, onClick } = propsreturn withNativeProps(props,<divclassName={classNames('adm-space', {'adm-space-wrap': props.wrap,'adm-space-block': props.block,[`adm-space-${direction}`]: true,[`adm-space-align-${props.align}`]: !!props.align,[`adm-space-justify-${props.justify}`]: !!props.justify,})}onClick={onClick}>{React.Children.map(props.children, child =>child === null || child === undefined ? null : (<div className="adm-space-item">{child}</div>))}</div>)
}
簡短工具實現(可參考):
function mergeProps<T>(defaults: Partial<T>, props: T): T {return { ...(defaults as any), ...(props as any) }
}function withNativeProps(props: any, node: React.ReactElement) {const { className, style, ...rest } = propsreturn React.cloneElement(node, {...rest,className: [node.props.className, className].filter(Boolean).join(' '),style: { ...(node.props.style || {}), ...(style || {}) },})
}
4. 樣式核心(要點)
- 使用 CSS 變量:
--gap
,--gap-horizontal
,--gap-vertical
- 默認
display: inline-flex
,block
時為display: flex
.adm-space-item { flex: none }
保證子項不被拉伸- vertical:item 用
margin-bottom
,最后一個取消 - horizontal:item 用
margin-right
,容器用負margin-right
抵消末尾多余空隙 - wrap:
flex-wrap: wrap
+ 外層負margin-bottom
+ itempadding-bottom
實現行間距
簡要 CSS:
.adm-space {display: inline-flex;--gap: 8px;--gap-horizontal: var(--gap);--gap-vertical: var(--gap);
}
.adm-space-item { flex: none; }.adm-space-horizontal { flex-direction: row; }
.adm-space-horizontal > .adm-space-item { margin-right: var(--gap-horizontal); }
.adm-space-horizontal:not(:empty) { margin-right: calc(var(--gap-horizontal) * -1); }.adm-space-vertical { flex-direction: column; }
.adm-space-vertical > .adm-space-item { margin-bottom: var(--gap-vertical); }
.adm-space-vertical > .adm-space-item:last-child { margin-bottom: 0; }.adm-space-wrap { flex-wrap: wrap; margin-bottom: calc(var(--gap-vertical) * -1); }
.adm-space-wrap > .adm-space-item { padding-bottom: var(--gap-vertical); }/* align / justify 映射到 align-items / justify-content */
5. 使用示例
<Space><Button>按鈕1</Button><Button>按鈕2</Button>
</Space><Space direction="vertical" style={{ '--gap': '16px' }}><div>行1</div><div>行2</div>
</Space><Space wrap style={{ '--gap-horizontal': '12px', '--gap-vertical': '8px' }}>{items.map(i => <Tag key={i}>{i}</Tag>)}
</Space>
自定義 gap:
<Space style={{ '--gap': '12px' }} />
簡單替代(現代瀏覽器支持 flex gap):
const SimpleSpace = ({children, gap='8px'}) => (<div style={{display:'inline-flex', gap}}>{React.Children.toArray(children).map((c,i)=> <div style={{flex:'none'}} key={i}>{c}</div>)}</div>
)
6. 關鍵設計理由(一句話)
通過包裹子項 + flex: none
+ margin/padding 組合,利用 CSS 變量暴露 gap,做到間距可控且不影響子元素布局;負 margin 處理容器末尾多余空隙。
以上就是筆者基于AI返回的解讀信息稍加了一些補充和修改,結合起來看源碼提效真是太多了,對于前端本身就是基于視圖所完成編碼,因此把組件邏輯層交給AI來解讀太適合不過了。
希望對大家有所幫助,共同學習源碼。