Skip to content

Commit c80e54b

Browse files
committed
feat: form add selfUpdate #1049
1 parent 0a419da commit c80e54b

File tree

4 files changed

+37
-12
lines changed

4 files changed

+37
-12
lines changed

components/form/Form.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export const FormProps = {
6363
hideRequiredMark: PropTypes.bool,
6464
autoFormCreate: PropTypes.func,
6565
options: PropTypes.object,
66+
selfUpdate: PropTypes.bool,
6667
};
6768

6869
export const ValidationRule = {

components/form/FormItem.jsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const FormItemProps = {
3434
colon: PropTypes.bool,
3535
fieldDecoratorId: PropTypes.string,
3636
fieldDecoratorOptions: PropTypes.object,
37+
selfUpdate: PropTypes.bool,
3738
};
3839
function comeFromSlot(vnodes = [], itemVnode) {
3940
let isSlot = false;
@@ -69,6 +70,11 @@ export default {
6970
data() {
7071
return { helpShow: false };
7172
},
73+
computed: {
74+
itemSelfUpdate() {
75+
return !!(this.selfUpdate === undefined ? this.FormProps.selfUpdate : this.selfUpdate);
76+
},
77+
},
7278
created() {
7379
this.collectContext();
7480
},
@@ -448,7 +454,7 @@ export default {
448454
}
449455
const option = this.decoratorOption(vnode);
450456
if (option && option[0]) {
451-
vnodes[i] = getFieldDecorator(option[0], option[1])(vnode);
457+
vnodes[i] = getFieldDecorator(option[0], option[1], this)(vnode);
452458
}
453459
}
454460
return vnodes;
@@ -466,7 +472,7 @@ export default {
466472
let child = filterEmpty($slots.default || []);
467473
if (decoratorFormProps.form && fieldDecoratorId && child.length) {
468474
const getFieldDecorator = decoratorFormProps.form.getFieldDecorator;
469-
child[0] = getFieldDecorator(fieldDecoratorId, fieldDecoratorOptions)(child[0]);
475+
child[0] = getFieldDecorator(fieldDecoratorId, fieldDecoratorOptions, this)(child[0]);
470476
warning(
471477
!(child.length > 1),
472478
'`autoFormCreate` just `decorator` then first children. but you can use JSX to support multiple children',

components/form/index.zh-CN.md

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
| form |`Form.create()` 包装过的组件会自带 `this.form` 属性,如果使用template语法,可以使用this.$form.createForm(this, options) | object ||
88
| hideRequiredMark | 隐藏所有表单项的必选标记 | Boolean | false |
99
| layout | 表单布局 | 'horizontal'\|'vertical'\|'inline' | 'horizontal' |
10+
| selfUpdate | 自定义字段更新逻辑,说明[见下](/components/form-cn/#selfUpdate),需1.3.17版本以上 | boolean | false |
1011

1112
### 事件
1213
| 事件名称 | 说明 | 回调参数 |
@@ -174,6 +175,7 @@ validateFields(['field1', 'field2'], options, (errors, values) => {
174175
| required | 是否必填,如不设置,则会根据校验规则自动生成 | boolean | false |
175176
| validateStatus | 校验状态,如不设置,则会根据校验规则自动生成,可选:'success' 'warning' 'error' 'validating' | string | |
176177
| wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol | [object](/components/grid-cn/#Col) | |
178+
| selfUpdate | 自定义字段更新逻辑,你可以通过 Form 的 selfUpdate 进行统一设置。当和 Form 同时设置时,以 Item 为准。 说明[见下](/components/form-cn/#selfUpdate) 需1.3.17版本以上 | boolean | false |
177179

178180
### 校验规则
179181

@@ -194,3 +196,9 @@ validateFields(['field1', 'field2'], options, (errors, values) => {
194196
更多高级用法可研究 [async-validator](https://github.com/yiminghe/async-validator)
195197

196198

199+
### selfUpdate
200+
201+
设置 `selfUpdate``true` 后,`Form` 通过增量方式更新,只更新被修改的字段。大部分场景下,你只需要编写代码即可。而在某些特定场景,例如修改某个字段值后出现新的字段选项、或者纯粹希望表单任意变化都需要进行渲染。你可以通过修改 Form.Item 取消 selfUpdate,或者在 `change` / `onValuesChange` 回调中手动调用 `this.$forceUpdate()` 更新组件。[示例]()
202+
203+
如果你并不精通 Vue,并不建议使用 selfUpdate,如果出现性能问题,可以尝试这把 Form 相关的业务独立到一个单独的组件中,减少组件渲染的消耗。
204+

components/vc-form/src/createBaseForm.jsx

+20-10
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ function createBaseForm(option = {}, mixins = []) {
6060
this.instances = {};
6161
this.cachedBind = {};
6262
this.clearedFieldMetaCache = {};
63-
63+
this.formItems = {};
6464
this.renderFields = {};
6565
this.domFields = {};
6666

@@ -172,8 +172,9 @@ function createBaseForm(option = {}, mixins = []) {
172172
return cache[action].fn;
173173
},
174174

175-
getFieldDecorator(name, fieldOption) {
175+
getFieldDecorator(name, fieldOption, formItem) {
176176
const { props, ...restProps } = this.getFieldProps(name, fieldOption);
177+
this.formItems[name] = formItem;
177178
return fieldElem => {
178179
// We should put field in record if it is rendered
179180
this.renderFields[name] = true;
@@ -341,17 +342,26 @@ function createBaseForm(option = {}, mixins = []) {
341342
setFields(maybeNestedFields, callback) {
342343
const fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields);
343344
this.fieldsStore.setFields(fields);
345+
const changedFields = Object.keys(fields).reduce(
346+
(acc, name) => set(acc, name, this.fieldsStore.getField(name)),
347+
{},
348+
);
344349
if (onFieldsChange) {
345-
const changedFields = Object.keys(fields).reduce(
346-
(acc, name) => set(acc, name, this.fieldsStore.getField(name)),
347-
{},
348-
);
349350
onFieldsChange(this, changedFields, this.fieldsStore.getNestedAllFields());
350351
}
351-
if (templateContext) {
352-
templateContext.$forceUpdate();
353-
} else {
354-
this.$forceUpdate();
352+
const formContext = templateContext || this;
353+
let allUpdate = false;
354+
Object.keys(changedFields).forEach(key => {
355+
let formItem = this.formItems[key];
356+
formItem = typeof formItem === 'function' ? formItem() : formItem;
357+
if (formItem && formItem.itemSelfUpdate) {
358+
formItem.$forceUpdate();
359+
} else {
360+
allUpdate = true;
361+
}
362+
});
363+
if (allUpdate) {
364+
formContext.$forceUpdate();
355365
}
356366
this.$nextTick(() => {
357367
callback && callback();

0 commit comments

Comments
 (0)