Skip to content

Commit 13737fe

Browse files
committed
feat(lib ui-schema): ui-schema 支持配置 ui:hidden 表达式实现数据联动
feat(lib ui-schema): ui-schema 支持配置 ui:hidden 表达式实现数据联动
1 parent 4a6f2ce commit 13737fe

File tree

6 files changed

+87
-54
lines changed

6 files changed

+87
-54
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ sidebarDepth: 2
1414
* [Todo: 通过 if else 实现联动](#通过-if-else-实现联动)
1515

1616
打破 `JSON Schema` 规范包含如下几种方式:
17-
17+
* 通过ui-schema配置表达式
1818
* [通过自定义组件配置 ui:field 使用已有联级组件](#通过-ui-field-调用自己的联级组件)
1919
* [通过 ui-schema fieldStyle 动态样式](#ui-schema-fieldstyle-实现联动)
2020

@@ -299,6 +299,10 @@ export default {
299299

300300
就目前来看 if else 比较容易解决数据联动的场景,可以根据值来做判断,但依旧不能解决对值支持逻辑判断,比如`大于``小于`,后续版本会考虑支持该特性。
301301

302+
### 通过ui-schema配置表达式
303+
可能打破 `JSON Schema` 规范,配置思想来源 [ali form-render](https://github.com/alibaba/form-render)
304+
305+
302306
### ui:field 调用自己的联级组件
303307
可能打破 `JSON Schema` 规范,**适用于通过配置一个已有的自定义组件来渲染一些复杂的联动场景**
304308

packages/docs/docs/zh/guide/todo.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
- [x] 优化源码 不需要this的组件调整为 functional
2323
- [x] 数组支持配置是否显示序号
2424
- [x] 数组渲染样式微调优化(控制条下间距等)
25-
- [ ] 支持属性依赖 [属性依赖](https://json-schema.org/understanding-json-schema/reference/object.html#property-dependencies)
25+
- [x] 支持属性依赖 [属性依赖](https://json-schema.org/understanding-json-schema/reference/object.html#property-dependencies)
26+
- [x] 支持 ui:hidden 使用 mustache 表达式
27+
- [ ] review 是否存在无key的数组子节点
28+
- [ ] 支持 所有ui和err配置使用 mustache 表达式
2629
- [ ] 支持Schema依赖 [Schema依赖](https://json-schema.org/understanding-json-schema/reference/object.html#schema-dependencies)
27-
2830
- [ ] 添加代码测试
2931
- [ ] 对照react schema from适配更多规则支持
3032
- [ ] 解耦elementUi 重新开发form 和formItem组件,通过配置化实现适配elementUi iView 等常用ui组件

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

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,52 @@
11
// eslint-disable-next-line import/no-cycle
22
import FIELDS_MAP from '../config/FIELDS_MAP';
33
import retrieveSchema from './schema/retriev';
4+
import { getPathVal } from './vueUtils';
45

56
import { isObject, getSchemaType } from './utils';
67

8+
// 配置表达式,或者常量,或者传入函数
9+
// 这里打破 JSON Schema 规范
10+
const regExpression = /{{(.*)}}/;
11+
function handleExpression(rootFormData, curNodePath, expression) {
12+
// 未配置
13+
if (undefined === expression) {
14+
return undefined;
15+
}
16+
17+
// 配置了 mustache 表达式
18+
const matchExpression = regExpression.exec(expression);
19+
regExpression.lastIndex = 0; // 重置索引
20+
if (matchExpression) {
21+
const code = matchExpression[1].trim();
22+
23+
// eslint-disable-next-line no-new-func
24+
const fn = new Function('parentFormData', 'rootFormData', `return ${code}`);
25+
26+
return fn(getPathVal(rootFormData, curNodePath, 1), rootFormData);
27+
}
28+
29+
// 配置了函数 function
30+
if (typeof expression === 'function') {
31+
return expression(getPathVal(rootFormData, curNodePath, 1), rootFormData);
32+
}
33+
34+
// 配置了常量 ??
35+
return expression;
36+
}
37+
738
// 是否为 hidden Widget
839
export function isHiddenWidget({
940
schema = {},
10-
uiSchema = {}
41+
uiSchema = {},
42+
curNodePath = '',
43+
rootFormData = {}
1144
}) {
1245
const widget = uiSchema['ui:widget'] || schema['ui:widget'];
13-
return widget === 'HiddenWidget' || widget === 'hidden';
46+
const hiddenExpression = uiSchema['ui:hidden'] || schema['ui:hidden'];
47+
48+
// 支持配置 ui:hidden 表达式
49+
return widget === 'HiddenWidget' || widget === 'hidden' || !!handleExpression(rootFormData, curNodePath, hiddenExpression);
1450
}
1551

1652
// 解析当前节点 ui field

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ export function setPathVal(obj, path, value) {
4444
}
4545

4646
// 获取当前path值
47-
export function getPathVal(obj, path) {
47+
export function getPathVal(obj, path, leftDeviation = 0) {
4848
const pathArr = path.split(pathSeparator);
4949

50-
for (let i = 0; i < pathArr.length; i += 1) {
50+
for (let i = 0; i < pathArr.length - leftDeviation; i += 1) {
5151
// 错误路径或者undefined中断查找
5252
if (obj === undefined) return undefined;
5353
obj = pathArr[i] === '' ? obj : obj[pathArr[i]];

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

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -41,57 +41,46 @@ export default {
4141
// hidden
4242
const hiddenWidget = isHiddenWidget({
4343
schema,
44-
uiSchema: props.uiSchema
44+
uiSchema: props.uiSchema,
45+
curNodePath: props.curNodePath,
46+
rootFormData: props.rootFormData
4547
});
4648

47-
// functional 渲染多节点
48-
const renderList = [];
49-
50-
const pathClassName = nodePath2ClassName(context.props.curNodePath);
49+
const pathClassName = nodePath2ClassName(props.curNodePath);
5150

5251
if (schema.anyOf && schema.anyOf.length > 0 && !isSelect(schema)) {
5352
// anyOf
54-
renderList.push(
55-
h(FIELDS_MAP.anyOf, {
56-
class: {
57-
[`${pathClassName}-anyOf`]: true,
58-
fieldItem: true,
59-
anyOfField: true
60-
},
61-
props: curProps
62-
})
63-
);
64-
} else if (schema.oneOf && schema.oneOf.length > 0 && !isSelect(schema)) {
53+
return h(FIELDS_MAP.anyOf, {
54+
class: {
55+
[`${pathClassName}-anyOf`]: true,
56+
fieldItem: true,
57+
anyOfField: true
58+
},
59+
props: curProps
60+
});
61+
} if (schema.oneOf && schema.oneOf.length > 0 && !isSelect(schema)) {
6562
// oneOf
66-
renderList.push(
67-
h(FIELDS_MAP.oneOf, {
68-
class: {
69-
[`${pathClassName}-oneOf`]: true,
70-
fieldItem: true,
71-
oneOfField: true
72-
},
73-
props: curProps
74-
})
75-
);
76-
} else {
77-
renderList.push(
78-
// 渲染对应子组件
79-
fieldComponent && h(hiddenWidget ? 'div' : fieldComponent, {
80-
props: {
81-
...curProps,
82-
fieldProps
83-
},
84-
class: {
85-
...context.data.class,
86-
[lowerCase(fieldComponent.name) || fieldComponent]: true,
87-
hiddenWidget,
88-
fieldItem: true,
89-
[pathClassName]: true
90-
}
91-
})
92-
);
63+
return h(FIELDS_MAP.oneOf, {
64+
class: {
65+
[`${pathClassName}-oneOf`]: true,
66+
fieldItem: true,
67+
oneOfField: true
68+
},
69+
props: curProps
70+
});
9371
}
94-
95-
return renderList;
72+
return (fieldComponent && !hiddenWidget) ? h(fieldComponent, {
73+
props: {
74+
...curProps,
75+
fieldProps
76+
},
77+
class: {
78+
...context.data.class,
79+
[lowerCase(fieldComponent.name) || fieldComponent]: true,
80+
hiddenWidget,
81+
fieldItem: true,
82+
[pathClassName]: true
83+
}
84+
}) : null;
9685
}
9786
};

packages/lib/src/JsonSchemaForm/fields/combiningSchemas/SelectLinkageField/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import {
66
getPathVal, setPathVal, deletePathVal, nodePath2ClassName
77
} from '../../../common/vueUtils';
8-
import { isEmptyObject, filterObject, guessType } from '../../../common/utils';
8+
import {
9+
isEmptyObject, filterObject, guessType, isObject
10+
} from '../../../common/utils';
911

1012
import { getWidgetConfig, getUserUiOptions, getUserErrOptions } from '../../../common/formUtils';
1113

@@ -100,7 +102,7 @@ export default {
100102
const curFormData = getPathVal(this.rootFormData, this.curNodePath);
101103

102104
// 移除旧key
103-
if (guessType(curFormData) === 'object') {
105+
if (isObject(curFormData)) {
104106
const oldSelectSchema = retrieveSchema(
105107
this.selectList[oldVal],
106108
this.rootSchema

0 commit comments

Comments
 (0)