一、Alert
组件的message
中除了接收字符串外,还能接收 DOM 节点。
<Alert
message={
<p>
<span>已选择 {selectedRowKeys.length} 项</span>
<a onClick={resetChecked} style={{ marginLeft: '24px' }}>清空</a>
</p>
}
type="info"
showIcon
/>
二、Form
表单高级搜索
收起时只显示前两个Form.Item
,展开显示全部。
const [expand, setExpand] = useState(false);
// 搜索框结构样式
const renderForm = () => {
return (
<Form form={form} onFinish={handleSearch}>
<Row gutter={24}>
<Col span={8}>
<Form.Item name="userName" label="用户名称"
getValueFromEvent={event => event.target.value.trim()}>
<Input placeholder="请输入用户名称" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="status" label="状态">
<Select placeholder="请选择状态" allowClear={true}>
<Option value="1">已启用</Option>
<Option value="0">未启用</Option>
</Select>
</Form.Item>
</Col>
<Col span={8} style={{ display: expand ? 'block' : 'none' }}>
<Form.Item name="classId" label="所属班级">
<Select placeholder="请选择班级" allowClear={true}>
{
classList.map(type =>
<Option key={type.fieldKey} value={type.fieldKey}>{type.fieldValue}</Option>
)
}
</Select>
</Form.Item>
</Col>
<Col span={8} style={{ display: expand ? 'block' : 'none' }}>
<Form.Item name="gradeId" label="所属年级">
<Select placeholder="请选择所属年级" allowClear={true}>
{
gradeList.map(type =>
<Option key={type.fieldKey} value={type.fieldKey}>{type.fieldValue}</Option>
)
}
</Select>
</Form.Item>
</Col>
<Col span={expand ? 16 : 8} style={{ textAlign: expand ? "right" : "left" }}>
<Button type="primary" htmlType="submit">查询</Button>
<Button style={{ marginLeft: 8 }} onClick={handleReset}>重置</Button>
<Button type="link" onClick={() => { setExpand(!expand) }}>
{expand ? <span>收起<UpOutlined /></span> : <span>展开<DownOutlined /></span>}
</Button>
</Col>
</Row>
</Form>
)
}
三、Form.Item
是<span>
元素问题
<Form.Item name="schedTime" label="时间">
<span style={{ marginRight: (schedTime || time) ? 8 : 0 }}>{time ? time : schedTime}</span>
<Button type="primary" onClick={openDialog}>设置时间规则</Button>
</Form.Item>
场景:在FormItem
里有一个<span>
和 一个<Button>
,点击按钮出现一个设置时间规则的组件,设置完成后的时间值,也就是一个字符串会在<span>
中显示。最后和其他表单项的值一起提交给后端接口。
问题一:表单填写完提交时没有<span>
元素中的值。
原因:因为form
默认只将带name
属性的input
标签的值提交。<span>
元素没有这个属性,需要手动设置它的值。
这里我是在打开设置时间规则组件时通过setFieldsValue
将值赋给FormItem
。
const getTimeRules = value => {
setTime(value);
form.setFieldsValue({ schedTime: value.trim() });
setVisibleDialog(false);
}
问题二:虽然时间值有了,但页面上不显示,不能及时改变,清空表单时时间值还在。
解决方法:定义了一个state
变量time
,用来显示的,实际传递给后端接口的还是schedTime
。
const [time, setTime] = useState("");
// 清空表单和数据
const clearForm = () => {
setTime("");
form.resetFields();
}
四、Form.Item
内有多个元素,控制台报错。
<Form.Item name="field" />
只会对它的直接子元素绑定表单功能,例如直接包裹了 Input/Select。如果控件前后还有一些文案或样式装点,或者一个表单项内有多个控件,你可以使用内嵌的Form.Item
完成。你可以给Form.Item
自定义style
进行内联布局,或者添加noStyle
作为纯粹的无样式绑定组件(类似 3.x 中的getFieldDecorator
)。
根据官网介绍,将第三点中Form.Item
的结构改为如下形式,就没有上面的错误了。
<FormItem label="时间">
<FormItem name="schedTime" noStyle>
<span style={{ marginRight: (schedTime || time) ? 8 : 0 }}>{time ? time : schedTime}</span>
</FormItem>
<Button type="primary" onClick={openDialog}>设置时间规则</Button>
</FormItem>
五、Form.Item
下的子组件defaultValue
不生效
<FormItem name="num" label="数字">
<InputNumber min={0} max={255} defaultValue={0} />
</FormItem>
一开始我使用上面的方法给InputNumber
设置了初始值,但没有生效,控制台还报错。
官网里有提到这个问题:当你为Form.Item
设置name
属性后,子组件会转为受控模式。因而defaultValue
不会生效。你需要在Form
上通过initialValues
设置默认值。
<Form initialValues={{ num: 0 }}>
<FormItem name="num" label="数字">
<InputNumber min={0} max={255} />
</FormItem>
</Form>
六、Form.Item
的noStyle
属性
为true
时不带样式。可编辑表格中的Form.Item
设置noStyle
之后,校验时不会出现下图中的效果。
七、 编辑页Select
下拉框回显id问题
场景:新增和编辑共用一个表单,下拉框之间有联动的效果,先选择某个年级,才能选择这个年级下的某个班级,接着才能选择这个班级下的某个学生。也就是三个下拉框之间的联动,下图有点问题…
注意:第一个和第二个下拉框编辑需要回显名称,实际传给接口的值是对应 id,第三个下拉框显示名称,传的值也是名称。
问题:最初第一个和第二个下拉框都是用onChange
事件,实现第一个下拉框值改变时获取到第二个下拉框下拉选项,这样刚进入编辑页回显时第二个下拉框回显的是 id 而不是班级名称。
原因:刚进入编辑页第一个下拉框的onChange
事件没有触发,第二个下拉框数组没有值。
新增页:
编辑页:
解决:将下拉框中的onChange
事件在useEffect
中调用,主要代码如下。
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'dva';
import { Form, Select, Button } from 'antd';
import { history, useLocation } from 'umi';
const FormItem = Form.Item;
const { Option } = Select;
const UpdatePage = () => {
const dispatch = useDispatch();
const [form] = Form.useForm();
const { query: { id } } = useLocation();
const gradeId = form.getFieldValue("gradeId");
const classId = form.getFieldValue("classId");
const { info, classList } = useSelector(state => state.student); // 某个年级下所有班级
// 编辑表单回显
useEffect(() => {
if (id) {
dispatch({...});
if (gradeId) {
getClassList(gradeId)
}
}
}, [id, gradeId])
return (
<Form form={form} onFinish={update}>
<FormItem name="gradeId" label="年级">
<Select allowClear placeholder="请选择"
onChange={key => getClassList(key)}>
{
gradeList.map(type =>
<Option key={type.fieldKey} value={type.fieldKey}>{type.fieldValue}</Option>
)
}
</Select>
</FormItem>
<FormItem name="classId" label="班级名称">
<Select allowClear placeholder="请选择" disabled={!gradeId}
onChange={key => getStudent(key)}>
{
classList.map(type =>
<Option key={type.fieldKey} value={type.fieldKey}>{type.fieldValue}</Option>
)
}
</Select>
</FormItem>
<FormItem name="student" label="学生姓名">
<Select allowClear mode="multiple" placeholder="请选择" disabled={!classId}>
{
studentList.map(item =>
<Option key={item} value={item}>{item}</Option>
)
}
</Select>
</FormItem>
<FormItem>
<Button onClick={clearForm}>取消</Button>
<Button type="primary" htmlType="submit">确定</Button>
</FormItem>
</Form>
)
};
export default UpdatePage;
七、Select
的onChange
事件的两个参数
Select
下拉框的onChange
事件,官方说明是选中option
,或input
的value
变化时,调用此函数。
function(value, option:Option | Array<Option>)
也就是说,接收两个参数value
和option
,option
可以是一个对象或者对象数组。
之前一直只用到value
参数,某天打印出了option
对象时就有点迷惑。
<Select
onChange={(value, option) => {
console.log(value);
console.log(option);
fn1(option.key);
fn2(option.value);
}}
>
{
userList.map(item =>
<Option key={item.userId} value={item.userName}>{item.userName}</Option>
)
}
</Select>
// 打印出的 option 对象
{
key: "1462050266472448",
value: "jack"
children: "jack"
}