dynamic-components v1.1.0
DictDynamicComponents 是一个基于 Vant Form 的动态表单组件,支持通过配置列表 componentList 动态渲染多种表单组件,具备表单数据双向绑定、灵活的显示/隐藏规则、自定义校验逻辑、响应式布局等功能,适用于复杂表单场景(如动态表单、条件显示表单、多类型组件混合表单等)。


基础动态表单
<template>
<DictDynamicComponents
v-model="formData"
:componentList="componentList"
@pass="handlePass"
@fail="handleFail"
@action="handleAction"
/>
</template>
<script setup>
import { ref } from 'vue';
// 表单数据
const formData = ref({
username: '',
age: null,
gender: 'male'
});
// 组件配置列表
const componentList = [
{
compName: 'VanField', // 组件名(Vant组件)
isFormData: true, // 是否绑定表单数据
fieldName: 'username', // 绑定的字段名
props: {
label: '用户名',
placeholder: '请输入用户名',
rules: [{ required: true, message: '用户名不能为空' }]
}
},
{
compName: 'VanField',
isFormData: true,
fieldName: 'age',
props: {
label: '年龄',
type: 'number',
placeholder: '请输入年龄'
}
},
];
// 校验通过回调
const handlePass = (formData, item) => {
console.log('表单校验通过', formData, item);
};
// 校验失败回调
const handleFail = (errors) => {
console.log('表单校验失败', errors);
};
// 校验失败回调
const handleAction = (item, formData) => {
console.log('action动作', item, formData);
};
</script>Props 说明
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | Object | {} | 表单数据对象(支持 v-model 双向绑定) |
rules | Object | {} | 全局表单验证规则,键为字段名,值为验证规则数组(同 Vant Form 规则) |
idField | String | "id" | 组件配置项中用于标识唯一ID的字段名(用于依赖排序) |
componentList | Array | [] | 动态组件配置列表(核心配置,每项为一个组件的详细配置,见下方说明) |
isScrollToFormError | Boolean | 空 | 有配置此属性时可覆盖全局 校验失败时是否自动滚动到错误位置 动态组件配置的此字段 |
| ... | - | 对应组件支持van-form的其他原生属性(如 VanField 的 type、VanSelect 的 options 等) |
组件配置项(componentList 每项属性)
| 属性名 | 类型 | 说明 |
|---|---|---|
compName | String | 组件名称(如 "VanField"、"VanSelect"、"VanRadioGroup" 等 Vant 组件) |
isFormData | Boolean | 是否绑定表单数据(true 则通过 fieldName 与 formData 关联) |
fieldName | String | 绑定的表单字段名(isFormData 为 true 时必填) |
hidden | Boolean | hidden为true时,无论如何组件都不可见 |
visible | Boolean | 初始可见性(默认 true,可通过 showRules 动态控制) |
showRules | Array,Object,String | 显示/隐藏规则(见下方「显示规则详解」) |
showRuleType | String | 显示规则类型(默认 全局动态组件配置的值 "compare",可选 "calculate"、"validate" 等) |
validatorRuleType | String | 验证规则类型(默认 全局动态组件配置的值 "compare",可选 "calculate" 等) |
props | Object | 组件属性(传递给 compName 对应的组件,如 label、placeholder 等) |
props 常用属性
| 属性名 | 类型 | 说明 |
|---|---|---|
label | String | 组件标签文本 |
placeholder | String | 占位提示文本(默认根据组件类型自动生成,如输入类为"请输入",选择类为"请选择") |
rules | Array | 组件级验证规则(优先级高于全局 rules,格式同 Vant Form 规则) |
required | Boolean | 是否必填(会自动关联验证规则) |
slotList | Array | 组件插槽配置(见下方「插槽说明」) |
| ... | - | 对应组件支持的其他原生属性(如 VanField 的 type、VanSelect 的 options 等) |
事件说明
| 事件名 | 说明 | 回调参数 |
|---|---|---|
pass | 表单校验通过时触发 | (formData: Object, trigger: any) - 校验通过的表单数据及触发源 |
fail | 表单校验失败时触发 | errors: Array - 校验失败的错误信息数组 |
action | 组件内部触发的action事件 | 该组件的配置 item 对象 (也就是componentList里面的具体一项),用于根据item值进行相应动作 |
方法说明
组件通过 defineExpose 暴露以下方法:
| 方法名 | 说明 | 返回值 |
|---|---|---|
getFormData | 获取当前可见组件的表单数据(自动过滤隐藏组件的字段) | 表单数据对象 |
resetFormData | 重置表单(恢复初始数据、重置验证状态、重新计算显示规则) | - |
getComponentRef | 获取指定字段的组件实例(不传参则返回所有组件实例) | 组件实例(或包含所有实例的对象) |
getDynamicComponentsRef | 获取底层 VanForm 组件实例 | VanForm 实例 |
显示规则详解(showRules)
showRules 用于动态控制组件的显示/隐藏,支持多种规则类型,结合 showRuleType 生效:
1. 基础比较规则(showRuleType: "compare")
通过比较表单数据的值控制显示
第一层数组表示或
总体规则(第一层数组)
[规则1]:表示 规则1 的结果,结果为 true 时显示该组件
[规则1,规则2,规则3] 表示 规则1||规则2||规则3 的结果,结果为 true 时显示该组件
第二层数组表示且
规则1的规则(第二层数组)
[[规则1-1,规则1-2,规则1-3],[规则2-1,规则2-2,规则2-3], [规则3-1,规则3-2,规则3-3]] 表示 (规则1-1&&规则1-2&&规则1-3) || (规则2-1&&规则2-2&&规则2-3) || (规则3-1&&规则3-2&&规则3-3)
第三次数组表示具体比较规则
规则1-1的规则(第三层数组)
["值", "运算符", "值"]
值使用 ${}包裹,表示获取formData表单数据的某个字段的值,可以使用.获取子字段的值
运算符支持如下:
常用运算符
<、>、==、===、!=、!==、>=、<=
特殊运算符
| 运算符 | 作用描述 | 示例条件配置 | 适用场景 |
|---|---|---|---|
in | 字段值是否在目标数组中 | ['${role}', 'in', ['admin', 'user']] | 检查角色是否在允许列表中 |
not in | 字段值是否不在目标数组中 | ['${status}', 'not in', ['deleted']] | 排除某些状态值 |
includes | 字符串/数组是否包含目标值 | ['${name}', 'includes', '张'] | 检查姓名是否包含“张”字 |
not includes | 字符串/数组是否不包含目标值 | ['${tags}', 'not includes', 'invalid'] | 检查标签中是否没有“invalid” |
between | 字段值是否在 [min, max] 闭区间内 | ['${score}', 'between', [60, 100]] | 检查分数是否在60-100之间 |
regex | 字段值是否匹配正则表达式 | ['${phone}', 'regex', /^1[3-9]\d{9}$/] | 验证手机号格式 |
startsWidth | 字段值以什么开头 | ['${phone}', 'startsWidth', '123'] | 验证手机号是否以123开头 |
endsWidth | 字段值是否以什么结尾 | ['${phone}', 'regex', '123'] | 验证手机号是否以123结尾 |
// 示例:当 gender 为 'female' 时显示该组件
showRules: [[['${gender}','===', 'female']]],
showRuleType: "compare"
// 示例:当 gender 为 'female' 或 'male' 时显示该组件
showRules: [[['${gender}','===', 'female']], [['${gender}','===', 'male']],
showRuleType: "compare"
// 示例:当 gender 为 'female' 且 like 为 'basketball' 时显示该组件
showRules: [[['${gender}','===', 'female'], ['${like}','===', 'basketball']]],
showRuleType: "compare"2. 计算规则(showRuleType: "calculate")
数组形式
第一层表示或 [规则1,规则2,规则3] 表示 规则1||规则2||规则3 的结果,结果为 true 时显示该组件
第二层表示且
[[规则1-1,规则1-2,规则1-3]] 表示 规则1-1&&规则1-2&&规则1-3 的结果,结果为 true 时显示该组件
第三层表示具体计算规则
也是数组形式 [变量1,运算符,变量2] 第一个元素为变量,第二个元素为运算符,第三个元素为变量
变量又可以套用上述计算规则 如 [[变量1-1,运算符,变量1-2], '>', 变量2] 变量可以无限套用上述规则
// 示例:当 age > 18 且 isStudent 为 false 时显示
showRules: [[["${age}", '>', 18], ["${isStudent}", '===', false]]],
showRuleType: "calculate"支持计算运算符和比较运算符
计算运算符 +、-、*、/、%、**
比较运算符 ===、!==、==、!=、>、<、>=、<=
:::注意
第一层的运算符仅支持 比较运算符 非第一层的运算符仅支持 计算运算符 为了方便数字计算,变量值为纯数字的字符串时会被转化为数字类型,因此比较时请注意。
:::
3. 校验规则(showRuleType: "validate")
通过其他字段的校验状态控制显示,支持数组形式和字符串形式,字符串需表示多个时使用英文逗号隔开
// 示例:当 username 和 password 校验通过时显示 username和password为fieldName对应字段
showRules: ['username', 'password'],
showRuleType: "validate"// 示例:当 username 和 password 校验通过时显示 username和password为fieldName对应字段
showRules: 'username,password',
showRuleType: "validate"4. 逻辑组合规则(showRuleType: "(1||2)&&(3||4)")
通过逻辑运算符组合多种规则(支持嵌套 compare、calculate、validate 类型)
// 示例:(gender为female 且 age>18) 或 email校验通过 时显示
showRules: [
{
type: "compare",
rules: [[['${gender}', '===', 'female' ], ['${age}', '>', 18]]]
},
{ type: "validate", rules: ['email'] }
],
showRuleType: "1||2" // 满足条件1 或 条件2即可验证规则详解
验证规则支持组件级 props.rules 和全局 rules,格式同 Vant Form,扩展功能如下:
1. 内置验证器
内置了许多常用校验规则,也可以通过 dictConfig.validator 配置进行覆盖和添加全局验证函数,在规则中通过字符串引用:
// 全局配置示例(store中的dictConfig)
dictConfig.validator = {
phone: (val) => /^1[3-9]\d{9}$/.test(val), // 手机号验证
idCard: (val) => /^\d{17}[\dXx]$/.test(val) // 身份证验证
};
// 组件配置中使用
props: {
rules: [{
validator: 'phone', // 引用全局验证器
message: '请输入正确的手机号'
}]
}2. 支持字符串格式的正则表达式
当rules配置的 pattern 为字符串格式时,会自动给他进行 new RegExp() 处理,使之变成 正则表达式
props: {
rules: [{
pattern: "^1[3-9]\\d{9}$", // 此字符串会被new RegExp()处理 变成 /^1[3-9]\d{9}$/ 也就是验证手机号的正则
message: '请输入正确的手机号'
}]
}3. 动态验证规则
与上面的显示隐藏基本一致,唯一不同就是此处没有"validate"类型;通过数组形式定义条件验证,结合 validatorRuleType 生效:
// 示例:邮箱必填 且 age 必须大于 18 验证才会通过
props: {
rules: [
{ required: true, message: '成年用户必须填写邮箱' }, // 验证规则
{
validator: [[["${age}", ">", 18]]]
}
]
},
validatorRuleType: "compare"// 示例:邮箱必填 且 age1 + age2 必须大于 18 验证才会通过
props: {
rules: [
{ required: true, message: '成年用户必须填写邮箱' }, // 验证规则
{
validator: [[[["${age1}", "+", "${age2}"], ">", 18]]]
}
]
},
validatorRuleType: "calculate"// 示例:邮箱必填 且 age1 + age2 必须大于 18 验证才会通过
props: {
rules: [
{ required: true, message: '成年用户必须填写邮箱' }, // 验证规则
{
validator: [
{
type: "calculate",
rules: [[["${age1}", "+", "${age2}"], ">", 18]]
},
{
type: "compare",
rules: [[["${age}", "<", 6]]]
}
]
}
]
},
validatorRuleType: "1||2"插槽说明
通过组件配置的 props.slotList 可自定义组件内容,slotList 每项配置:
| 属性名 | 类型 | 说明 |
|---|---|---|
| slotName | String | 插槽名称(如 "label"、"suffix" 等组件支持的插槽) |
| render | Function,String | 渲染函数,入参为 { scope, formData }(scope为插槽作用域,formData为当前表单数据) |
示例:
props: {
slotList: [
{
slotName: "suffix", // 自定义后缀插槽
render: "<span class=\"custom-suffix\">{{username ? '已输入username' : '未输入username'}}</span>"
}
]
}布局说明
组件对表单组件支持响应式布局,非表单组件默认百分百占比,根据屏幕宽度自动调整组件宽度:
- 屏幕宽度 < 768px:默认占满宽度
- 768px ≤ 宽度 < 1024px:默认占 50% 宽度
- 1024px ≤ 宽度 < 1400px:默认占 33.333% 宽度
- 宽度 ≥ 1400px:默认占 25% 宽度
可通过给组件添加类名强制指定宽度:
full:占 100% 宽度half:占 50% 宽度three:占 33.333% 宽度four:占 25% 宽度
示例:
props: {
class: 'half' // 强制占50%宽度
}
