什么是formilyjs?
Formily 是一个用于构建高性能、可扩展的表单解决方案的 JavaScript 库。虽然 Formily 提供了许多有用的功能,但在使用过程中可能会遇到一些常见的痛点。以下是一些可能的问题:
- 学习曲线:Formily 具有自己的一套概念和 API,因此使用者需要花时间学习和理解其工作原理。这可能对于初次接触 Formily 的开发者来说是一个挑战。
- 配置复杂性:Formily 提供了丰富的配置选项和功能,以满足各种表单需求。然而,这也可能导致配置变得复杂,特别是对于较为复杂的表单。开发者需要仔细研究文档和示例,以正确配置和使用 Formily。
- 缺乏文档和示例:尽管 Formily 的文档已经在不断完善,但仍然可能存在一些缺失或不完整的部分。有时候可能会遇到一些缺乏示例或详细说明的情况。文档也比较分散,不是很好查找。
如何使用$self.value
例1:生成选项的uuid,保证ArrayCards中每一个数组的唯一值
{
"uuid": {
"x-component": "Input",
"x-decorator": "FormItem",
"x-hidden": true,
"x-reactions": {
"fulfill": {
"state": {
"value": "{{ $self.value ? $self.value : uuid()}}"
}
},
"dependencies": [
{
"property": "value",
"type": "any"
}
]
},
"title": "选项UUID",
"type": "string"
}
}
在schema中,self.value很有用,当uuid已经有值的时候,不会重新生成新的uuid。
例2:根据Input中的数量自动生成多少个选项
Object.assign(correctAnswerExample, {
'x-reactions': [
{
dependencies: [inputDataSource.toString()],
fulfill: {
schema: {
default:
"{{(function(){ const answerNumber = $deps[0] || 0; const values = new Array(answerNumber).fill(''); const oldValues = $self.value;const valueList = values.map((item, index) => { if(oldValues?.[index]) { return oldValues[index]; } return { id: String(index) }; }); return valueList; })()}}"
}
}
}
]
});
- inputDataSource为某个元素的name
- default 里面支持一个自执行函数的字符串,如answerNumber为3,生成3个选项,当answerNumber改为4,生成4个选项。根据$self.value,当存在的值返回存在的数据,当不存在的值,返回仅有id属性的对象。
- default的自执行函数
{{(function(){
const answerNumber = $deps[0] || 0;
const values = new Array(answerNumber).fill('');
const oldValues = $self.value;
const valueList = values.map((item, index) => {
if(oldValues?.[index]) { return oldValues[index]; }
return { id: String(index) };
});
return valueList;
})()
}}
例3: 根据数量生成选项的下拉框,例如:选项1,选项2,选项3。当数量修改为2,可以过滤选中的下拉框值。
{
"type": "string",
"x-decorator": "FormItem",
"title": "对应问题空格",
"x-component": "Select",
"x-component-props": {
"mode": "multiple"
},
"x-reactions": {
"dependencies": [
{
"property": "value",
"type": "any",
"source": "questionInfo.answerArea.imageAnswerAreaContent",
"name": "answers"
},
{
"property": "value",
"type": "any",
"source": "determineInfo.type",
"name": "type"
}
],
"fulfill": {
"state": {
"display": "{{(function(){ return $form?.values?.determineInfo.type === 1 ? 'visible' : 'hidden'; })()}}",
"componentProps": {
"options": "{{ (function(){ const options = []; const imageAnswerAreaContent = $form?.values?.questionInfo?.answerArea?.imageAnswerAreaContent; for (let i = 0; i < imageAnswerAreaContent?.length; i++) { const { id } = imageAnswerAreaContent[i]; options.push({ label: '选项' + (i + 1), value: id }); } options.push({ label: '干扰项', value: -1 }); return options; })() }}"
},
"value": "{{ (function(){ const ids = $deps.answers?.map(it => it.id) || []; const values = $self.value?.filter(id => [...ids, -1]?.includes(id)); return values; })() }}"
}
}
}
}
- options的生成
{{ (function(){
const options = []; const imageAnswerAreaContent = $form?.values?.questionInfo?.answerArea?.imageAnswerAreaContent;
for (let i = 0; i < imageAnswerAreaContent?.length; i++) {
const { id } = imageAnswerAreaContent[i];
options.push({ label: '选项' + (i + 1), value: id }); }
options.push({ label: '干扰项', value: -1 });
return options; })()
}}
- value数据的过滤
{{ (function(){
const ids = $deps.answers?.map(it => it.id) || [];
const values = $self.value?.filter(id => [...ids, -1]?.includes(id));
return values; })()
}}
setValues设置不生效?
我们项目由于是动态获取的表单Schema,如果我们在获取到表单Schema之前调用createForm初始化表单实例,会导致setValues设置表单数据不生效。解决方案:
获取到表单schema之后,设置:
formRef.current = createForm({
validateFirst: true
});
表单
{formRef.current && (
<Form
labelCol={3}
wrapperCol={16}
form={formRef.current}
previewTextPlaceholder='-'
size='large'
layout='horizontal'>
<SchemaField schema={normalSchema} />
<Affix offsetBottom={30}>
<div style={{ display: 'flex', justifyContent: 'right', marginTop: 20 }}>
<Button
style={{ marginRight: 20 }}
取消
</Button>
<Button type='primary' onClick={onOk} loading={loading.save}>
保存
</Button>
</div>
</Affix>
</Form>
)}
设置数据方法,就是必须先存着formRef.current,再渲染表单,不然设置表单值会失败。感觉是formily的一个bug。
formRef.current.setValues(res.data);
表单无数据情况下,默认显示:N/A,用previewTextPlaceholder可以重新自定义默认值。
根据radio隐藏显示字段,如富文本显示富文本相关字段,图片显示图片相关字段。
{
"properties": {
"answerAreaType": {
"type": "number",
"title": "类型",
"x-decorator": "FormItem",
"x-component": "Radio.Group",
"default": 0,
"enum": [
{
"label": "富文本",
"value": 0
},
{
"label": "图片",
"value": 1
}
]
},
"richType": {
"type": "void",
"title": "富文本类型",
"x-reactions": {
"dependencies": [
{
"property": "value",
"type": "any",
"source": ".answerAreaType",
"name": "type"
}
],
"fulfill": {
"state": {
"display": "{{(function(){ return $deps.type === 0 ? 'visible' : 'hidden'; })()}}"
}
}
},
"properties": {}
},
"imageType": {
"type": "void",
"title": "图片类型",
"rule": {},
"x-reactions": {
"dependencies": [
{
"property": "value",
"type": "any",
"source": ".answerAreaType",
"name": "type"
}
],
"fulfill": {
"state": {
"display": "{{(function(){ return $deps.type === 1 ? 'visible' : 'hidden'; })()}}"
}
}
},
"properties": {}
}
}
}
依赖的字段路径
dependencies的路径,可以写全路径,也就是表单提交数据的结构,如:questionInfo.answerArea.imageAnswerAreaContent,找到imageAnswerAreaContent字段
如果字段唯一,也可以*.answerAreaType用*模糊匹配
相对路径
相对路径语法主要是在数据型路径头部用点语法表示,对于计算数组的相邻元素非常好用,它主要有几个特点:
- 一个点代表当前路径
- 每个层级用两个点,..向上寻找。
x-index,可以用作属性的排序。但x-index不能重复,否则重复的属性,只会显示一个
如何给某个地方添加提示信息,给Typography组件设置属性children,style等就可以完成添加提示信息。
{
"info": {
"type": "void",
"x-component": "Space",
"x-index": 3,
"properties": {
"spaceTitle": {
"x-component": "Typography.Text",
"x-component-props": {
"children": "说明:",
"style": {
"color": "#8a8f8d"
}
}
},
"spaceText1": {
"x-component": "Typography.Text",
"x-component-props": {
"children": "1、通用数学逻辑 支持数学符号 xxxxxxx",
"style": {
"color": "#8a8f8d"
}
}
}
},
"title": "Space",
"x-component-props": {
"title": "Space",
"direction": "vertical",
"style": {
"marginBottom": "10px"
}
}
}
}