предисловие
Эта статья используется для записи сбора ям для майнинга при использовании компонентов, связанных с andt, и определения границ возможностей компонентов.
Руководство пользователя формы
1. Двусторонняя привязка данных к this.props.form
Ключевые слова: GetFieldDecorator
Используйте поля, которые получают пакеты FetfieldDecorator автоматически, и форма является бидвардной, и доступна только упаковка getfieldDecorator.
getFieldsValue
getFieldValue
setFieldsValue
Ждатьdemo:
<FormItem
{...formItemLayout}
label='name'}
>
{getFieldDecorator('name', {})(
<Input />
)}
</FormItem>
В это время имя поля будет двунаправленно привязано к this.props.form.name, и нет необходимости, чтобы onChange явно управлял значением.При отправке все обернутые поля появятся в свойствах формы.
Однако, если вы хотите реализовать привязку формы, вы можете управлять другими полями только через onChange и this.props.form.setFieldsValue. Лично я считаю, что это недостаточно элегантно. Если его можно напрямую привязать к состоянию, это будет намного освежать.
Уведомление:
- В Form.Item рекомендуется помещать только один дочерний элемент, украшенный с помощью getFieldDecorator, когда есть несколько украшенных дочерних элементов,
help
required
validateStatus
Не может быть сгенерирован автоматически. 2.2.0
Ранее он автоматически генерировался только в том случае, если поле формы было дочерним по отношению к Form.Item.help
required
validateStatus
, ситуацию гнездования необходимо установить самостоятельно.- Вы больше не можете использовать value/defaultValue для установки значения формы, вы можете использовать только initialValue для его установки.
- Вы не можете украсить чистый компонент, в конце концов, это декоратор. . .
2. Взаимодействие данных формы с компонентами верхнего уровня
Ключевые слова: mapPropsToFields, onFieldsChange, onValuesChange
mapPropsToFields: сопоставление свойств родительского компонента с элементами формы (можно использовать для считывания значений в хранилище Redux)
onfieldschange: когда
Form.Item
Запускается при изменении значения дочернего узла, вы можете сбросить соответствующее значение в хранилище Redux.demo:
@Form.create({
mapPropsToFields(props) {
// 使用上层组件的scope的值作为表单的数据
const { scope } = props;
return {
nickname: Form.createFormField({
value: scope.nickname,
}),
phone: Form.createFormField({
value: scope.phone,
}),
address: Form.createFormField({
value: scope.address,
}),
agreement: Form.createFormField({
value: scope.agreement,
}),
};
},
onValuesChange(props, values) {
// 将表单的变化值回填到上层组件的scope中
props.onFormChange(values);
},
})
Это дает возможность взаимодействовать с компонентами верхнего уровня, что полезно для сценариев, в которых данные находятся в хранилище.
3. Богатая проверка
Ключевые слова: правила
demo:
<FormItem
{...formItemLayout}
label='text'
extra={this.confirmNode()}
>
{getFieldDecorator('subscribe', {
initialValue: subscribe,
rules: [{
required: true,
message: ‘message’,
}],
})(
<Receiver subscribe={subscribe} onReceiverChange={this.onReceiverChange} />
)}
</FormItem>
Правила поля можно легко установить с помощью существующих правил проверки.
4. Пользовательская проверка
Ключевые слова: валидатефиелдс/валидатефиелдсандскролл
demo:
checkFormConfig = (rule, value, cb) => {
if (value.length === 0) {
cb('规则不能为空');
}
}
...
<FormItem >
{getFieldDecorator('config', {
initialValue: 'init value',
rules: [{
validator: this.checkFormConfig,
}],
})(
<RuleConfig
alarmConfig={alarmConfig}
/>
)}
</FormItem>
value — значение поля, cb — проверочная информация, отображаемая при возникновении ошибки, но cb необходимо вызывать
5. Пользовательские компоненты
Ключевые слова: управляемый режим
Предоставление контролируемых свойствvalue
или другойvaluePropNameОдноименное значение. поставкаonChange
событие илиtriggerЗначение события с тем же именем. Не может быть функциональным компонентом.
Использование пользовательских компонентов в формах следует приведенным выше соглашениям.
Примечание. При использовании проверки для пользовательских компонентов необходимо обращать внимание на область действия, поскольку antd добавит стиль валидатора-ошибки во все поля ввода компонента ошибки, и даже в раскрывающемся списке будут напоминания.
6. Вложенность полей формы пользовательских компонентов
Если в вашем компоненте есть только один элемент формы, вы можете использовать непосредственное использование вышеперечисленного, но компоненты содержат SUMS, вы не можете использовать FormiteM во внешнем слое.
...
<FormItem>
</FormItem>
<Parent /> //不用在Parent外面包装Item,在实际使用input的地方使用
class Parent extend PureComponent {
render () {
return <Child />
}
}
class Child extend PureComponent {
render () {
<FormItem> // 在实际的输入上加Item
{
getFieldDecorator('continuous', {
initialValue: continuous,
rules: [
{
required: true,
message: 'please input u continuous',
},
{
validator: this.validate,
},
],
})(
// 绝对不用在这里包裹div,不然就接收不到change
<Select
onChange={this.onChangeContinuous}
>
{continuousList}
</Select>
)
}
</FormItem>
}
}
Если это подкомпонент с карты, вам нужно убедиться, что идентификатор getFieldDecorator отличается, иначе все идентификаторы привязаны к значению
7. Получите значение пользовательского компонента
Например, пользовательский компонент — это
class MyComponent extends PureComponent {
constructor(){
super();
this.state = {
receiverList: [],// 受控属性
}
}
onReceiverChange = receiverList => {
this.setState({ receiverList });
// 用于Form的回调
if (this.props.onChange) {
this.props.onChange(receiverList);
}
}
render() {
const receiverList = this.state.receiverList;
return (
<Input onChange={this.onReceiverChange} value={receiverList}/>
);
}
}
Просто напишите это в форме:
...
<Form>
<Form.Item>
{getFieldDecorator('receiverList', {
rules: [{
required: true,
message: 'Please input name!',
}],
})(
<Receiver receiverList />
)}
</Form.Item>
</Form>
ReceiverList — это управляемое свойство в пользовательском компоненте. Теперь контролируемое свойство в пользовательском компоненте назначено на form.receiverList, и им также можно управлять по правилу формы, разве не здорово~
Божья яма: если это элемент формы, такой как select, никогда не пишите div снаружи
<Form>
<Form.Item>
{getFieldDecorator('receiverList', {
rules: [{
required: true,
message: 'Please input name!',
}],
})(
//<div> 绝对不要在这里加div,否则不能获取select的change事件!!!!!
<Select>
<Option value=1>1</Option>
</Select>
)}
</Form.Item>
</Form>
Руководство пользователя всплывающей подсказки
1. Нажмите всплывающую подсказку
демо:
<Popconfirm
title={intl.find('alarm.attributes.sureToDelete')}
trigger="click"
onClick={this.onDelete(alarmId)}
>
<Icon
type="delete"
/>
</Popconfirm>
Очень распространенный пример: при нажатии на значок появляется всплывающее окно подтверждения.
Однако, когда вы щелкнете по диаграмме, вы обнаружите, что popconfirm мелькает и непосредственно выполняет событие onDelete.Почему?
Поскольку popconfirm предоставляет onConfirm, при нажатии на значок всплывает событие click, поэтому onClick запускается в popconfirm. Зная процесс, восстановление также очень просто, а именно:
<Popconfirm
title={intl.find('alarm.attributes.sureToDelete')}
trigger="click"
onConfirm={this.onDelete(alarmId)} // 使用正确的监听函数
>
<Icon
type="delete" onClick={evt => {
evt.stopPropagation(); // 阻止事件冒泡
}}
/>
</Popconfirm>
2. Проблема попконфирминги в гнездо
Если ваш проект дизайна имеет вложенную связь с popconfirm, это выглядит следующим образом:
<Popover
placement="bottomRight"
content={content}
trigger="click"
visible={this.state.visible}
onVisibleChange={this.handVisibleChange}
overlayClassName="xri-alarm-config-popover"
>
<i
className={`${alarms.length > 0 && alarms[0].alarmObject.status === 'NORMAL' ?
'alarm-config-icon_useable' : 'alarm-config-icon'} feature-icon`}
title={intl.find('charts.wrapHead.alarmConfig.title')}
onClick={this.changVisible}
/>
</Popover>
content:
<Popconfirm
title='title'
onConfirm={this.onConfirm}
onCancel={this.onCancel}
okText='ok'
cancelText='取消'
visible={this.isShowPopConfirm(index)}
getPopupContainer={this.getPopupContainer}
onVisibleChange={this.handVisibleChange}
overlayClassName="xri-alarm-popconfirm-sync"
>
<Tooltip title={intl.find('alarm.edit')} trigger="hover">
<span className="icon" onClick={this.checkSync(item, index)}>
<Icon type="edit"/>
</span>
</Tooltip>
</Popconfirm>
Вы обнаружите, что когда вы нажимаете внутреннее всплывающее окно, все элементы управления класса всплывающей подсказки во внешнем слое отключаются, что удивительно. . .
Постарайтесь предотвратить всплытие внутреннего события, чтобы верхний компонент не реагировал на событие, идеальная идея, разумная, приятная.
Впрочем, бесполезно, ну большой ход, исходники все решают.
В документации rc-toolTip есть очень важное описание
Function returning html node which will act as tooltip container. By default the tooltip attaches to the body. If you want to change the container, simply return a new element.
основаниеre-triggerЭто написано:
getContainer = () => {
const { props } = this;
const popupContainer = document.createElement('div');
// Make sure default popup container will never cause scrollbar appearing
// https://github.com/react-component/trigger/issues/41
popupContainer.style.position = 'absolute';
popupContainer.style.top = '0';
popupContainer.style.left = '0';
popupContainer.style.width = '100%';
const mountNode = props.getPopupContainer ?
props.getPopupContainer(findDOMNode(this)) : props.getDocument().body;
mountNode.appendChild(popupContainer);
return popupContainer;
}
Другими словами, все компоненты на основе всплывающих подсказок имеют тело в качестве родительского компонента по умолчанию, поэтому внешние компоненты, которые предотвращают всплытие, по-прежнему затрагиваются. на самом деле re-tigger предоставляет API для изменения родителя по умолчанию, а antd также предоставляет этот API для разработки, т.е.
getPopupContainer
, после изменения родительского отношения ваше видимое событие не повлияет на другие компоненты, но обратите внимание на класс, потому что меняется уровень, поэтому структуру css необходимо соответствующим образом скорректировать.загрузить руководство по использованию
1. Обнаружение файлов
Предоставляет возможность обнаружения перед загрузкой, а также может определять количество файлов, типы файлов, размеры файлов и т. д.
function beforeUpload(file, fileList) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
const isGteMax = fileList.length > 3;
if (!isJPG) {
message.error('You can only upload JPG file!');
}
if (!isLt2M) {
message.error('Image must smaller than 2MB!');
}
if(isGteMax) {
message.error('Image count smaller than 4');
}
return isJPG && isLt2M && isGteMax;
}
...
<Upload
className="avatar-uploader"
name="avatar"
showUploadList={false}
action="//jsonplaceholder.typicode.com/posts/"
beforeUpload={beforeUpload}
multiple=true
onChange={this.handleChange}
>
<Button>upload</Button>
</Upload>
2. Ручная загрузка
загрузка выбрана по умолчанию для прямой загрузки файлов.Если вы хотите загружать вручную после завершения некоторой бизнес-логики, вы можете использовать beforeUpload для возврата false, загружать файлы вручную и использовать new FormData();
ps: FormData
import { Upload, Button, Icon, message } from 'antd';
import reqwest from 'reqwest';
class Demo extends React.Component {
state = {
fileList: [],
uploading: false,
}
handleUpload = () => {
const { fileList } = this.state;
const formData = new FormData();
fileList.forEach((file) => {
formData.append('files[]', file);
});
this.setState({
uploading: true,
});
// You can use any AJAX library you like
reqwest({
url: '//jsonplaceholder.typicode.com/posts/',
method: 'post',
processData: false,
data: formData,
success: () => {
this.setState({
fileList: [],
uploading: false,
});
message.success('upload successfully.');
},
error: () => {
this.setState({
uploading: false,
});
message.error('upload failed.');
},
});
}
render() {
const { uploading } = this.state;
const props = {
action: '//jsonplaceholder.typicode.com/posts/',
onRemove: (file) => {
this.setState(({ fileList }) => {
const index = fileList.indexOf(file);
const newFileList = fileList.slice();
newFileList.splice(index, 1);
return {
fileList: newFileList,
};
});
},
beforeUpload: (file) => {
this.setState(({ fileList }) => ({
fileList: [...fileList, file],
}));
return false;
},
fileList: this.state.fileList,
};
return (
<div>
<Upload {...props}>
<Button>
<Icon type="upload" /> Select File
</Button>
</Upload>
<Button
className="upload-demo-start"
type="primary"
onClick={this.handleUpload}
disabled={this.state.fileList.length === 0}
loading={uploading}
>
{uploading ? 'Uploading' : 'Start Upload' }
</Button>
</div>
);
}
}
ReactDOM.render(<Demo />, mountNode);
3. Настройте поведение загрузки
Когда вам нужно настроить поведение длинной загрузки, вы в основном используете customRequest для реализации пользовательского действия загрузки по умолчанию.
/* eslint no-console:0 */
import React from 'react';
import ReactDOM from 'react-dom';
import Upload from 'rc-upload';
import axios from 'axios';
const uploadProps = {
action: '/upload.do',
multiple: false,
data: { a: 1, b: 2 },
headers: {
Authorization: '$prefix $token',
},
onStart(file) {
console.log('onStart', file, file.name);
},
onSuccess(ret, file) {
console.log('onSuccess', ret, file.name);
},
onError(err) {
console.log('onError', err);
},
onProgress({ percent }, file) {
console.log('onProgress', `${percent}%`, file.name);
},
customRequest({
action,
data,
file,
filename,
headers,
onError,
onProgress,
onSuccess,
withCredentials,
}) {
// EXAMPLE: post form-data with 'axios'
const formData = new FormData();
if (data) {
Object.keys(data).map(key => {
formData.append(key, data[key]);
});
}
formData.append(filename, file);
axios
.post(action, formData, {
withCredentials,
headers,
onUploadProgress: ({ total, loaded }) => {
onProgress({ percent: Math.round(loaded / total * 100).toFixed(2) }, file);
},
})
.then(({ data: response }) => {
onSuccess(response, file);
})
.catch(onError);
return {
abort() {
console.log('upload progress is aborted.');
},
};
},
};
const Test = () => {
return (
<div
style={{
margin: 100,
}}
>
<div>
<Upload {...uploadProps}>
<button>开始上传</button>
</Upload>
</div>
</div>
);
};
ReactDOM.render(<Test />, document.getElementById('__react-content'));
конец
На данный момент границы возможностей Form, ToolTip и Upload обобщены, и я надеюсь, что это будет полезно для всех~