Ant Design 目前被广泛应用于企业级后台项目,甚至会被作为对外站点的 UI 库选择,构建 C 端业务。
目前我所在的公司就是使用 Ant Design 来构建网页。开发过程中比较常用的一些组件和它的使用方式,我也写了几篇文章,有兴趣的读者可以阅读:
本期我们将继续这个系列,讨论的对象是关于如何实现单行多列表单布局。如果你经常跟表单页面打交道,那么对这个布局方式应该并不陌生。
老规矩,我们先从创建项目开始。
创建项目
使用 Vite 的 React 模板。
npm create vite@latest my-react-app -- --template react
Scaffolding project in /Users/xt02121/pg/my-react-app...
Done. Now run:
cd my-react-app
npm install
npm run dev
进入项目,安装依赖:
cd my-react-app
npm install
npm run dev
使用 VS Code 打开项目:
code .
安装 @vitejs/plugin-react-swc 依赖,加快项目编译(可选):
npm i -D @vitejs/plugin-react-swc
// vite.config.js
import { defineConfig } from 'vite'
+ import react from '@vitejs/plugin-react-swc'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()]
})
安装 Ant Design 依赖:
npm install antd
删除 src/index.css 中的内容,src/App.jsx 改成下面这样:
import { FormDemo } from './FormDemo'
function App() {
return (
<FormDemo />
)
}
export default App
创建 FormDemo.jsx:
import { Form, Input, Button } from 'antd'
export function FormDemo() {
return <Form style={{ width: 600 }}>
<Form.Item label="用户名">
<Input placeholder="请输入用户名" />
</Form.Item>
<Form.Item label="密码">
<Input.Password placeholder="请输入密码" />
</Form.Item>
<Form.Item>
<Button htmlType="submit">登录</Button>
</Form.Item>
</Form>
}
查看效果:
接下来进入正文,来看看 Ant Design 中如何实现单行多列的表单布局。
<Form> layout="inline"
<Form> 提供了一个 layout prop,可以帮助我们最快实现行内多列布局。
- <Form style={{ width: 600 }}>
+ <Form layout='inline' style={{ width: 600 }}>
效果如下:
你会发现,设置成行业布局以后,每一个 .ant-form-item 会设置 margin-inline-end: 16px; 外边距,在默认文档流下,就是右外边距。
<Space size={16}>
当然,在不设置 <Form> layout prop 情况下,我们还可以通过 <Space> 控制表单项在一行展示。
- import { Form, Input, Button } from 'antd'
+ import { Form, Input, Button, Space } from 'antd'
<Form style={{ width: 600 }}>
+ <Space size={16}>
{/* ... */}
+ </Space>
<Form>
移除 layout prop,同时将 <Form.Item> 们包裹在 <Space> 之中(size 指定项目间的间隔,这里设置成 16px)。
查看效果:
发现与上面一样。可以看到,<Space> 其实就是一个 Flex 容器,其中的元素默认就是横向排列的,设置的 size 其实就是在指定 gap 属性,约定项目间的间隔。
当然,有时还会遇到一个表单字段是由多个输入框构成的情况。
这个时候,就要搭配 <Form.Item label> + <From.Item noStyle> 一起使用了。
<Form.Item label="BirthDate" style={{ marginBottom: 0 }}>
<Space size={16}>
<Form.Item name="year" noStyle rules={[{ required: true }]}>
<Input placeholder="Input birth year" />
</Form.Item>
<Form.Item name="month" noStyle rules={[{ required: true }]}>
<Input placeholder="Input birth month" />
</Form.Item>
</Space>
</Form.Item>
没有 name 和 rules 的 <Form.Item label="BirthDate"> 就只是单纯用来展示 Label 标签的;而设置了 noStyle 的 <Form.Item> 不会实际渲染 HTML 结构,但依然会保留表单字段收集和校验的能力。
而 <Form.Item label>、<From.Item noStyle> 之间的 <Space> 则是用来保证两个输入字段可以一行排列。
<Space.Compact>
除了 <Space>,还有 <Space.Compact> 帮助我们实现更加紧凑的表单布局。
<Space.Compact>
<Form.Item>
<Input placeholder="请输入用户名" />
</Form.Item>
<Form.Item>
<Input.Password placeholder="请输入密码" />
</Form.Item>
<Form.Item>
<Button htmlType="submit">登录</Button>
</Form.Item>
</Space.Compact>
查看效果:
发现表单是一行排列了,但表单之间的分割线会有点粗。这是因为 <Form.Item> 中的元素默认是有边框样式的,那么拼在一起自然会多出 1 像素的粗度。
这个问题可以通过给 <Form.Item> 设置 noStyle prop 搞定:
<Space.Compact>
<Form.Item noStyle>
<Input placeholder="请输入用户名" />
</Form.Item>
<Form.Item noStyle>
<Input.Password placeholder="请输入密码" />
</Form.Item>
<Form.Item noStyle>
<Button htmlType="submit">登录</Button>
</Form.Item>
</Space.Compact>
给 <Form.Item> 设置 noStyle 后,最终渲染出来的 HTML 中不包含 <Form.Item> 的结构(不过 <Form.Item> 的校验逻辑还会保留),相当于把内部元素的结构暴露出来了。
效果如下:
发现元素之间的边线变成 1 恢复正常了。
这是因为除第一个和最后一个的元素的边框都设置成 0 了。
<Row>、<Col> vs <Space>
不过使用 <Space> 实现多表单一行布局会有个限制,就是即便表单容器很宽,但内部输入框的宽度也不会自动扩展到容器的边界。
以以下代码为例:
<Form>
<Form.Item label="地址">
<Space size={16}>
<Form.Item
name={["address", "province"]}
noStyle
rules={[{ required: true, message: "Province is required" }]}
>
<Select placeholder="Select province">
<Select.Option value="Zhejiang">Zhejiang</Select.Option>
<Select.Option value="Jiangsu">Jiangsu</Select.Option>
</Select>
</Form.Item>
<Form.Item
name={["address", "street"]}
noStyle
rules={[{ required: true, message: "Street is required" }]}
>
<Input placeholder="Input street" />
</Form.Item>
</Space>
</Form.Item>
</Form>
渲染效果如下:
但实际内容区宽度占据了整个剩余的宽度的:
这个就可以考虑使用 <Row>、<Col> 了。
<Form.Item label="地址">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name={["address", "province"]}
noStyle
rules={[{ required: true, message: "Province is required" }]}
>
<Select placeholder="Select province">
<Select.Option value="Zhejiang">Zhejiang</Select.Option>
<Select.Option value="Jiangsu">Jiangsu</Select.Option>
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name={["address", "street"]}
noStyle
rules={[{ required: true, message: "Street is required" }]}
>
<Input placeholder="Input street" />
</Form.Item>
</Col>
</Row>
</Form.Item>
- 将
<Space size={16}>替换为<Row gutter={16}>,同时 - 使用
<Col>包裹每一个<Form.Item>,同时指定spanprop。Ant Design 设计系统将每一行<Row>分成 24 等份,<Col span={12}>就表示当前的<Col>占据 1/2 行宽。
效果如下:
至此,我们就实现了能够填充预留宽度的多列布局方式。
总结
本文我讲解了如何在 Ant Design 中实现单行多列表单的布局方式。包括:<Form> layout="inline"、<Space size={16}>、<Space.Compact> 以及 <Row> 和<Col>。
<Form>layout="inline" 是最简单的实现方式<Space size={16}>、<Space.Compact>则是用来实现局部字段一行布局- 当你期望表单能够自动扩展占据剩余宽度的效果时,可以考虑
<Row>和<Col>的组织方式
从 1 到 3,组织方式是一点点复杂的,而灵活度是慢慢增加的,你可以根据实际场景需要选择合适的方法。
好了,希望本文的介绍对你的工作能有所帮助。感谢你的阅读,再见。