表单与选择组件
目录
简介
本文档详细阐述了LMEs Web Base项目中的表单与选择类组件架构设计。该系统包含三个核心组件:DyForm动态表单引擎、Select组件系统以及DateTimePickRange日期时间选择器。这些组件共同构成了一个完整的表单解决方案,支持JSON Schema驱动的UI渲染、实时校验规则、懒加载选项、远程搜索等功能。
项目结构概览
图表来源
DyForm动态表单引擎
架构设计
DyForm是一个基于JSON Schema的动态表单引擎,采用Vue 3 Composition API和TypeScript构建。它通过预定义的组件映射表实现不同表单控件的动态渲染。
图表来源
JSON Schema驱动的UI渲染
DyForm通过formItemElementMap实现组件映射,支持多种表单控件类型:
const formItemElementMap: Record<string, any> = markRaw({
input: DyInput,
inputNumber: ElInputNumber,
select: Select,
selectInput: SelectInput,
flow: RelationFlowDialog,
variable: Variable,
textareaFlow: TextareaFlow,
switch: (props: PropType<any>, { attrs }: SetupContext) => {
return <el-switch {...attrs} />
},
})
实时校验规则
DyForm集成了Element Plus的表单验证系统,支持复杂的校验规则链:
const validate = () => {
if (!formRef.value) return false
return new Promise((resolve, reject) => {
formRef.value?.validate((valid: boolean) => {
if (valid) {
resolve(true)
} else {
reject(false)
}
})
})
}
章节来源
Select组件系统
图表来源
Element Plus封装ElSelect
ElSelect是对Element Plus Select组件的封装,主要用于特定配置场景:
return (
<el-config-provider namespace={namespace} z-index={500}>
<el-select
empty-values={[null, undefined]}
value-on-clear={undefined}
{...attrs}
disabled={disabled}
class="cs-setting-select_custom_style"
popper-class="settings-cs-select_check"
>
{options
? options.map((item: any) => {
return <Option {...item} />
})
: slots.default?.()}
</el-select>
</el-config-provider>
)
下拉选项懒加载与远程搜索
虽然当前实现主要依赖静态选项,但框架已为懒加载和远程搜索预留了扩展点:
// 选项数据源处理
const options = computed(() => {
return (
props.optionData?.value ||
(props.optionData as Array<any>) ||
props.options
)
})
多 选标签溢出处理
Radio组件实现了多选标签的智能处理:
// 多tag情况处理
if (Array.isArray(props.data)) {
return props.data.map((item: DataType, index: any) => {
return (
<div class={styles.tag} key={index}>
{item.name || item.label || item.description || item.type}
{props.showClose ? (
<Icon
class={styles.tagClose}
icon="tag_close"
onClick={(evt) => onClose(item, evt)}
/>
) : null}
</div>
)
})
}
章节来源
日期时间选择器
Vue 3响应式系统深度集成
DateTimePickRange组件展示了Vue 3响应式系统的最佳实践:
图表来源
时间范围联动机制
const onChangeFrom = (val: Date) => {
if (times.To && dayjs(val).isAfter(times.To)) {
ElMessage.warning(_t('开始时间必须比结束时间小'))
return
}
emit('change', times)
}
const onChangeTo = (val: Date) => {
if (times.To && dayjs(val).isBefore(times.From)) {
ElMessage.warning(_t('开始时间必须比结束时间小'))
return
}
emit('change', times)
}
国际化日期格式适配
组件支持多语言环境下的日期格式化:
const isZh = ref(true)
const checkZh = (lang: string) => {
const languageStr = lang.toLowerCase()
if (languageStr.includes('zh')) return true
if (languageStr.includes('original')) return true
return false
}
onMounted(() => {
isZh.value = checkZh(getCurrentLang())
onLanguageChange()
})
章节来源
性能优化策略
节流输入处理
虽然当前组件未显式实现节流,但可以通过以下方式优化:
// 推荐的节流实现
import debounce from 'lodash/debounce'
const handleInputChange = debounce((value: string) => {
// 处理输入变化
}, 300)
虚拟滚动选项列表
对于大量选项的场景,可以考虑实现虚拟滚动:
// 虚拟滚动示例结构
const VirtualSelect = defineComponent({
setup() {
const visibleOptions = ref([])
const scrollTop = ref(0)
const calculateVisibleOptions = () => {
// 计算可见选项逻辑
}
return () => (
<div
class="virtual-list"
onScroll={calculateVisibleOptions}
>
{visibleOptions.value.map(option => (
<Option {...option} />
))}
</div>
)
}
})
组件缓存策略
DyForm使用markRaw避免不必要的响应式代理:
const formItemElementMap: Record<string, any> = markRaw({
input: DyInput,
inputNumber: ElInputNumber,
// ... 其他组件
})
最佳实践指南
表单重置模式
// DyForm重置方法
const resetForm = () => {
if (!formRef.value) return false
formRef.value.resetFields()
}
// 手动重置示例
const manualReset = () => {
formItemProps.value.forEach((item: FormItemPropType) => {
form.value[item.prop] = item.defaultValue
})
}
默认值填充策略
// 初始化表单数据
const initFormData = () => {
formItemProps.value.forEach((item: FormItemPropType) => {
form.value[item.prop] = form.value[item.prop] || item.defaultValue
})
active.value = formItemProps.value[0].name
}
错误处理模式
// 验证错误处理
const validateWithErrorHandling = async () => {
try {
await validate()
return true
} catch (error) {
ElMessage.error('表单验证失败,请检查输入')
return false
}
}
故障排除
常见问题与解决方案
1. 动态表单组件未正确渲染
问题: JSON Schema中的el字段不匹配任何已注册组件
解决方案:
// 确保组件已正确注册到formItemElementMap
const customWidgetMap = {
myCustomComponent: MyCustomComponent
}
// 在DyForm中使用
<DyForm
customWidgetMap={customWidgetMap}
formItemProps={schema}
/>
2. 选择器选项不显示
问题: optionData或options属性为空
解决方案:
// 确保选项数据正确传递
<Select
optionData={computedOptions}
v-model={selectedValue}
/>
3. 日期范围验证失效
问题: 时间范围验证逻辑未正确执行
解决方案:
// 添加自定义验证规则
const customRules = [
{
validator: (rule, value, callback) => {
if (value.From && value.To && dayjs(value.From).isAfter(value.To)) {
callback(new Error('开始时间不能晚于结束时间'))
} else {
callback()
}
},
trigger: 'change'
}
]
章节来源
总结
LMEs Web Base的表单与选择组件系统展现了现代前端开发的最佳实践。通过DyForm动态表单引擎的JSON Schema驱动架构、Select组件系统的双重实现策略、以及DateTimePickRange的响应式集成,该系统提供了完整的表单解决方案。
关键特性包括:
- 灵活的动态表单渲染:支持多种表单控件类型的JSON Schema驱动渲染
- 强大的选择器系统:提供自研增强型和Element Plus封装两种选择
- 深度响应式集成:充分利用Vue 3的响应式系统特性
- 国际化支持:完整的多语言环境适配
- 性能优化:合理的组件缓存和渲染策略
这套组件系统不仅满足了当前业务需求,还为未来的功能扩展和性能优化奠定了坚实的基础。