Skip to content

Commit 1cda05d

Browse files
committed
feat(vjsf dependencies): 支持 object dependencies property ,scheam 依赖不支持
1 parent 267582c commit 1cda05d

File tree

4 files changed

+131
-49
lines changed

4 files changed

+131
-49
lines changed

packages/demo/src/index/views/Demo/schemaTypes/91.Object-property-dependencies/index.js

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,54 @@
44

55
export default {
66
schema: {
7-
title: 'Property dependencies',
8-
description: 'These samples are best viewed without live validation.',
7+
title: '单向依赖',
8+
description: '最基本的属性单向依赖,ui-schema 配置 onlyShowIfDependent 只在被依赖时才显示',
99
type: 'object',
1010
properties: {
1111
unidirectional: {
1212
title: 'Unidirectional',
13-
src: 'https://spacetelescope.github.io/understanding-json-schema/reference/object.html#dependencies',
13+
type: 'object',
14+
'ui:options': {
15+
onlyShowIfDependent: true
16+
},
17+
properties: {
18+
name: {
19+
title: 'Name',
20+
type: 'string'
21+
},
22+
credit_card: {
23+
title: 'Credit card',
24+
type: 'string'
25+
},
26+
billing_address: {
27+
title: 'Billing address',
28+
type: 'string'
29+
}
30+
},
31+
required: [
32+
'name'
33+
],
34+
dependencies: {
35+
credit_card: [
36+
'billing_address'
37+
]
38+
}
39+
},
40+
bidirectional: {
41+
title: '双向依赖',
42+
description: '显式地定义双向依赖,如果配置 onlyShowIfDependent 会导致初始化没有值时都无法渲染,这里需要使用者执行考虑',
1443
type: 'object',
1544
properties: {
1645
name: {
46+
title: 'Name',
1747
type: 'string'
1848
},
1949
credit_card: {
20-
type: 'number'
50+
title: 'Credit card',
51+
type: 'string'
2152
},
2253
billing_address: {
54+
title: 'Billing address',
2355
type: 'string'
2456
}
2557
},
@@ -29,6 +61,9 @@ export default {
2961
dependencies: {
3062
credit_card: [
3163
'billing_address'
64+
],
65+
billing_address: [
66+
'credit_card'
3267
]
3368
}
3469
}

packages/docs/docs/zh/guide/adv-config.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ sidebarDepth: 2
55
# 高级配置
66

77
## 数据联动
8-
* 数据联动的实现需要 `JSON Schema` [anyOf](https://form.lljj.me/#/demo?type=AnyOf) [oneOf](https://form.lljj.me/#/demo?type=OneOf) 格式来实现
9-
* 详细 AnyOf、oneOf 配置请 [点击查看](/zh/rules/combining.html)
108

11-
:::tip
12-
如果觉得 anyOf 配置麻烦也可以使用 [ui:field 使用已有联级组件](/zh/guide/adv-config.html#demo-联级选择),或者配置 [ui-schema fieldStyle](/zh/guide/basic-config.html#ui-schema) 通过样式隐藏来实现。
13-
:::
9+
要实现数据联动可以有多种方法来实现
10+
11+
* 通过 [anyOf](https://form.lljj.me/#/demo?type=AnyOf) 配置
12+
> 详细 AnyOf、oneOf 配置请 [点击查看](/zh/rules/combining.html)
13+
14+
* 通过 object dependencies 实现联动
15+
* 通过 if else 实现联动 Todo
16+
* 自定义组件配置 [ui:field 使用已有联级组件](/zh/guide/adv-config.html#demo-联级选择)
17+
* 通过 [ui-schema fieldStyle](/zh/guide/basic-config.html#ui-schema) 动态配置 style样式隐藏显示
18+
19+
### anyOf 实现数据联动
1420

1521
anyOf联动如下演示:(点击 `保存` 按钮查看 `formData` 数据)
1622

@@ -175,6 +181,20 @@ export default {
175181

176182
>* 推荐使用 `anyOf``oneOf` 只能有一个符合的结果
177183
184+
### object dependencies 实现数据联动
185+
186+
object dependencies 目前只支持属性联动,schema联动不支持暂时的计划也不打算支持。
187+
188+
### 通过 if else 实现联动
189+
目前来看 if else 比较容易解决数据联动的场景,且可以根据值来判断但依旧不支持逻辑表达式
190+
191+
### 通过 ui:field 调用自己的联级组件
192+
打破 JSON Schema 规范
193+
194+
### ui-schema fieldStyle 实现联动
195+
打破 JSON Schema 规范
196+
因为 ui-schema和formData 本身都是响应式数据,所以完全可以动态动态 ui-schema的值,并且像有些类似框架直接提供了 使用函数表达式的能力
197+
178198
## 树形结构
179199
* 树形结构需要使用 `$ref` 来递归调用自己
180200
* 详细 `$ref` 配置请 [点击查看](https://json-schema.org/understanding-json-schema/structuring.html?highlight=definitions#reuse)

packages/lib/src/JsonSchemaForm/common/utils.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
*/
44

55
// is object
6-
export function isObject(thing) {
7-
if (typeof File !== 'undefined' && thing instanceof File) {
8-
return false;
9-
}
10-
return typeof thing === 'object' && thing !== null && !Array.isArray(thing);
6+
export function isObject(object) {
7+
return Object.prototype.toString.call(object) === '[object Object]';
118
}
129

1310
// is arguments

packages/lib/src/JsonSchemaForm/fields/ObjectField/index.js

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
*/
44

55
import vueProps from '../props';
6-
76
import { orderProperties, getUiOptions } from '../../common/formUtils';
8-
import { computedCurPath } from '../../common/vueUtils';
9-
7+
import { computedCurPath, getPathVal } from '../../common/vueUtils';
8+
import { isObject } from '../../common/utils';
109
import FieldGroupWrap from '../../fieldComponents/FieldGroupWrap';
1110
import Widget from '../../fieldComponents/Widget';
1211

@@ -15,26 +14,50 @@ import SchemaField from '../SchemaField';
1514

1615
export default {
1716
name: 'ObjectField',
18-
props: {
19-
...vueProps
20-
},
21-
methods: {
22-
isRequired(name) {
23-
const schema = this.schema;
24-
return Array.isArray(schema.required) && !!~schema.required.indexOf(name);
25-
}
26-
},
27-
render(h) {
28-
const self = this;
29-
const props = this.$props;
17+
functional: true,
18+
props: vueProps,
19+
render(h, context) {
3020
const {
3121
schema,
3222
uiSchema,
3323
errorSchema,
34-
} = props;
24+
needValidFieldGroup,
25+
curNodePath,
26+
rootFormData
27+
} = context.props;
28+
29+
// required
30+
const isRequired = name => Array.isArray(schema.required) && !!~schema.required.indexOf(name);
31+
32+
// 存在 dependencies 配置,需要当前属性是否存在依赖关系 和当前属性是否正在被依赖
33+
// tip: 判断依赖关系需要使用了 formData 的值来做判断,所以当用户输入的时候会触发整个对象树重新渲染
34+
// TODO: 每个属性都需要单独来遍历 dependencies 属性可以优化一点点点点点(可通过 key value 反转值加个缓存来计算)
35+
const isDependOn = (name) => {
36+
let isDependency = false; // 是否是一个被依赖项
37+
let curDependent = false; // 当前是否触发依赖
38+
39+
if (isObject(schema.dependencies)) {
40+
curDependent = Object.entries(schema.dependencies).some(([key, value]) => {
41+
42+
// 是否和当前属性存在依赖关系
43+
const tempDependency = !!(Array.isArray(value) && ~value.indexOf(name));
44+
45+
// 是否是一个被依赖项
46+
isDependency = isDependency || tempDependency;
47+
48+
// 当前需要依赖
49+
return tempDependency && getPathVal(rootFormData, curNodePath)[key] !== undefined;
50+
});
51+
}
52+
53+
return {
54+
isDependency,
55+
curDependent
56+
};
57+
};
3558

3659
const {
37-
title, description, showTitle, showDescription, order, fieldClass, fieldAttrs, fieldStyle
60+
title, description, showTitle, showDescription, order, fieldClass, fieldAttrs, fieldStyle, onlyShowIfDependent
3861
} = getUiOptions({
3962
schema,
4063
uiSchema
@@ -44,19 +67,26 @@ export default {
4467
const orderedProperties = orderProperties(properties, order);
4568

4669
// 递归参数
47-
const propertiesVNodeList = orderedProperties.map(name => h(
48-
SchemaField,
49-
{
50-
props: {
51-
...props,
52-
schema: schema.properties[name],
53-
uiSchema: uiSchema[name],
54-
errorSchema: errorSchema[name],
55-
required: self.isRequired(name),
56-
curNodePath: computedCurPath(props.curNodePath, name)
70+
const propertiesVNodeList = orderedProperties.map((name) => {
71+
const required = isRequired(name);
72+
const { isDependency, curDependent } = isDependOn(name);
73+
74+
return h(
75+
// onlyShowWhenDependent 只渲染被依赖的属性
76+
(isDependency && onlyShowIfDependent && !curDependent) ? null : SchemaField,
77+
{
78+
key: name,
79+
props: {
80+
...context.props,
81+
schema: schema.properties[name],
82+
uiSchema: uiSchema[name],
83+
errorSchema: errorSchema[name],
84+
required: required || curDependent,
85+
curNodePath: computedCurPath(curNodePath, name)
86+
}
5787
}
58-
}
59-
));
88+
);
89+
});
6090

6191
return h(
6292
FieldGroupWrap,
@@ -67,7 +97,7 @@ export default {
6797
showTitle,
6898
showDescription
6999
},
70-
class: fieldClass,
100+
class: { ...context.data.class, ...fieldClass },
71101
attrs: fieldAttrs,
72102
style: fieldStyle
73103
},
@@ -81,23 +111,23 @@ export default {
81111
...propertiesVNodeList,
82112

83113
// 插入一个Widget,校验 object组 - minProperties. maxProperties. oneOf 等需要外层校验的数据
84-
this.needValidFieldGroup ? h(Widget, {
114+
needValidFieldGroup ? h(Widget, {
85115
class: {
86116
validateWidget: true,
87117
'validateWidget-object': true
88118
},
89119
props: {
90-
schema: Object.entries(self.$props.schema).reduce((preVal, [key, value]) => {
120+
schema: Object.entries(schema).reduce((preVal, [key, value]) => {
91121
if (
92-
self.$props.schema.additionalProperties === false
122+
schema.additionalProperties === false
93123
|| !['properties', 'id', '$id'].includes(key)
94124
) preVal[key] = value;
95125
return preVal;
96126
}, {}),
97127
uiSchema,
98128
errorSchema,
99-
curNodePath: props.curNodePath,
100-
rootFormData: props.rootFormData
129+
curNodePath,
130+
rootFormData
101131
}
102132
}) : null
103133
]

0 commit comments

Comments
 (0)