# 高级配置
# 数据联动
如下演示:
TIP
点击 保存
按钮查看 formData
数据
- 推荐使用
anyOf
,oneOf
只能有一个符合的结果- 后续版本会考虑通过
uiSchema
配置函数表达式来实现类似交互效果
# 树形结构
- 树形结构需要使用
$ref
来递归调用自己 - 详细
$ref
配置请 点击查看
WARNING
- $ref 不支持跨文件调用
uiSchema
errorSchema
暂不支持递归配置,需要逐级配置 Orz...
如下demo:
# 空数据默认值
默认在用户输入时如果清空了表单的数据为空时,即空字符串 ''
,会默认设置值为 undefined
,这样是为了保证和JSON Schema 规范保持一致。
可以通过配置 uiSchema
ui:emptyValue
的值来重置空数据默认值。
如下: 试试清空 firstName
lastName
输入框的值
- 提示:
JSON.stringify
转字符串时默认会丢弃undefined
的值,所以清空时没有firstName
- 参考
# 自定义样式
# 重置form表单默认样式
针对整个form默认样式,审查元素通过css覆盖即可,根css类名 genFromComponent
# 重置表单widget组件样式
如果是对 widget 组件的样式设置,可以通过 uiSchema
配置 style
、class
来重置你的样式
查看详细 uiSchema重置表单widget样式
# 根据当前表单渲染的节点类名重置样式
在渲染form表单时会根据schema的数据结构对每个 field
渲染节点生成唯一的 path
路径,并标记在class属性中,可通过该class选择器来重置某个局部样式。
如:
TIP
所有标记为路径的css类名,统一为 __path
前缀,其中 anyOf
,oneOf
同一个path 路径会存在多处渲染,可能会存在重复 path className
# 自定义Widget
自定义Widget通过配置 uiSchema
ui:widget
字段
- 类型:
String
|Object
|Function
可直接传入Vue组件,或者已注的组件名,或者resolve 了Vue组件的 async 函数,参加 $createElement,通过调用 $createElement
创建 Vnode
。
- 使用场景:需要自定义输入组件,比如结合业务的
图片上传
商品选择
等等
TIP
- 自定义的
Widget
组件必须接受一个双向绑定的值
# 自定义Field
自定义Field通过配置 uiSchema
ui:field
字段
- 类型:String | Object | Function
可直接传入Vue组件,或者已注的组件名,或者resolve 了Vue组件的 async 函数,参加 $createElement,通过调用 $createElement
创建 Vnode
。
参数格式和 自定义Widget 一致
- 使用场景:需要完全自定义某个节点的场景,相对比较复杂
- 自定义Filed会直接接管后续节点的渲染,意味着自定义节点后渲染逻辑都需要使用者自行处理,推荐在渲染子节点中继续调用
Vjsf
的SchemaField
组件,再交给Vjsf
去继续渲染。 - 组件内部一般会包含
FormItem
,校验规则
,Widget
输入组件
Field组件
会接受以下参数:
可以直接通过 vjsf
导入props配置,已经包含了上面的参数
import { fieldProps } from '@lljj/vue-json-schema-form';
- 演示:对图片和链接配置需要定义自己的ui效果
LinkImgField
代码如下:
<template>
<div :class="$style.box">
<el-form-item
:label="selectProps.title"
:prop="curNodePath"
:class="$style.elFormItem"
:rules="[
{
validator(rule, value, callback) {
const validProperties = ['imgUrl', 'imgLink'];
// 针对叶子节点做校验
let errors = [];
const isValidate = validProperties.every(item => {
errors = schemaValidate.validateFormDataAndTransformMsg({
formData: value[item],
schema: $props.schema.properties[item],
customFormats: $props.customFormats,
errorSchema: $props.errorSchema[item],
required: $props.schema.required.includes(item),
propPath: $props.curNodePath
});
return errors.length <= 0;
});
if (isValidate) return callback();
return callback(errors[0].message);
},
}
]"
:required="elItemRequired"
>
<div v-if="selectProps.description" :class="$style.description" v-html="selectProps.description"></div>
<div :class="$style.formItem">
<div :class="$style.uploadBox" @click="selectImg">
<img v-if="imgUrl" :src="imgUrl" alt="" style="max-width: 100%;max-height: 100%;">
<i v-else class="el-icon-plus"></i>
</div>
<el-input
v-model="imgLink"
:class="$style.input"
:placeholder="placeholder"
size="medium"
></el-input>
</div>
</el-form-item>
</div>
</template>
<script>
// 覆盖默认field 做个性商品选择和链接输入
import {
fieldProps,
vueUtils,
formUtils,
schemaValidate
} from '@lljj/vue-json-schema-form';
export default {
name: 'LinkImgField',
props: fieldProps,
data() {
return {
schemaValidate,
vueUtils
};
},
computed: {
elItemRequired() {
// 配置了 required 的属性提示小红点
return this.schema.required.length > 0;
},
placeholder() {
const imgLinkOptions = formUtils.getUiOptions({
schema: this.schema.properties.imgLink,
uiSchema: this.uiSchema.imgLink || {}
});
return imgLinkOptions.placeholder || '请输入合法的链接';
},
selectProps() {
return formUtils.getUiOptions({
schema: this.schema,
uiSchema: this.uiSchema
});
},
curValue() {
return vueUtils.getPathVal(this.rootFormData, this.curNodePath);
},
imgUrl: {
get() {
return this.curValue.imgUrl;
},
set(value) {
vueUtils.setPathVal(this.rootFormData, vueUtils.computedCurPath(this.curNodePath, 'imgUrl'), value);
}
},
imgLink: {
get() {
return this.curValue.imgLink;
},
set(value) {
vueUtils.setPathVal(this.rootFormData, vueUtils.computedCurPath(this.curNodePath, 'imgLink'), value);
}
}
},
methods: {
selectImg() {
const imgs = [
'https://gw.alicdn.com/tfs/TB1DKP9zCtYBeNjSspkXXbU8VXa-1920-450.jpg_Q90.jpg',
'https://aecpm.alicdn.com/simba/img/TB1W4nPJFXXXXbSXpXXSutbFXXX.jpg',
'https://aecpm.alicdn.com/simba/img/TB1_JXrLVXXXXbZXVXXSutbFXXX.jpg',
'https://img.alicdn.com/tfs/TB1FrlZPAzoK1RjSZFlXXai4VXa-1000-320.jpg',
'https://img.alicdn.com/tfs/TB1n5sCMYvpK1RjSZPiXXbmwXXa-900-320.jpg',
'https://img.alicdn.com/tps/i4/TB1ecCsOCzqK1RjSZPxSuw4tVXa.jpg',
'https://img.alicdn.com/tps/i4/TB1tVhuNhnaK1RjSZFBSuwW7VXa.jpg',
'https://img.alicdn.com/tfs/TB1IyonQVXXXXXCXXXXXXXXXXXX-750-200.jpg',
'https://gw.alicdn.com/tfs/TB1hJ2KX6ihSKJjy0FlXXadEXXa-254-318.png',
'https://gw.alicdn.com/tfs/TB1UE5RaCWD3KVjSZSgXXcCxVXa-720-400.jpg',
'https://gw.alicdn.com/tfs/TB11iC2uAzoK1RjSZFlXXai4VXa-254-318.jpg',
'https://gw.alicdn.com/tfs/TB1xo26qeH2gK0jSZFEXXcqMpXa-330-316.jpg',
'https://img.alicdn.com/bao/uploaded/i3/2781891994/O1CN01usHqqQ1QbILCMqrJm_!!2781891994.jpg',
'https://img.alicdn.com/bao/uploaded/i1/TB1M31ANFXXXXaOXpXXwu0bFXXX.png',
'https://img.alicdn.com/imgextra/i2/143584903/O1CN01qdnUD81m5cPPJlXog_!!143584903.jpg'
];
this.$message.success('选择图片成功,随机一个图片');
this.imgUrl = imgs[Math.floor(Math.random() * imgs.length)];
}
}
};
</script>
<style module lang="stylus">
.box {
:global {
.el-form-item__label {
font-weight: bold;
}
.el-form-item.is-error {
:local {
.uploadBox {
color: #F56C6C;
}
}
}
}
}
:global {
.arrayOrderList_item {
:local {
.elFormItem {
margin-bottom: 0;
}
}
}
}
.formItem {
align-items: center;
display: flex;
}
.input {
flex: 1;
margin-left: 5px;
}
.description {
font-size: 12px;
line-height: 20px;
margin-bottom: 10px;
color: #999;
}
.uploadBox {
cursor: pointer;
width: 60px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
background-color: #F2F2F2;
}
</style>