Form and Selection Components
Table of Contents
- Introduction
- Project Structure Overview
- DyForm Dynamic Form Engine
- Select Component System
- Date Time Picker
- Performance Optimization Strategies
- Best Practices Guide
- Troubleshooting
- Summary
Introduction
This document elaborates on the architecture design of form and selection components in the LMEs Web Base project. The system includes three core components: DyForm dynamic form engine, Select component system, and DateTimePickRange date time picker. These components together form a complete form solution, supporting JSON Schema-driven UI rendering, real-time validation rules, lazy loading options, remote search, and other features.
Project Structure Overview
Chart Source
DyForm Dynamic Form Engine
Architecture Design
DyForm is a dynamic form engine based on JSON Schema, built with Vue 3 Composition API and TypeScript. It implements dynamic rendering of different form controls through a predefined component mapping table.
Chart Source
JSON Schema-Driven UI Rendering
DyForm implements component mapping through formItemElementMap, supporting multiple form control types:
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} />
},
})
Real-Time Validation Rules
DyForm integrates Element Plus's form validation system, supporting complex validation rule chains:
const validate = () => {
if (!formRef.value) return false
return new Promise((resolve, reject) => {
formRef.value?.validate((valid: boolean) => {
if (valid) {
resolve(true)
} else {
reject(false)
}
})
})
}
Section Source
Select Component System
Chart Source
Element Plus Wrapper ElSelect
ElSelect is a wrapper for the Element Plus Select component, mainly used for specific configuration scenarios:
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>
)
Lazy Loading and Remote Search for Dropdown Options
Although the current implementation mainly relies on static options, the framework has reserved extension points for lazy loading and remote search:
// Option data source processing
const options = computed(() => {
return (
props.optionData?.value ||
(props.optionData as Array<any>) ||
props.options
)
})
Multiple Tag Overflow Handling
The Radio component implements intelligent handling of multiple tags:
// Multiple tag handling
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>
)
})
}
Section Source
Date Time Picker
Deep Integration with Vue 3 Reactive System
The DateTimePickRange component demonstrates best practices for Vue 3's reactive system:
Chart Source
Time Range Linkage Mechanism
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)
}
Internationalized Date Format Adaptation
The component supports date formatting in multilingual environments:
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()
})
Section Source
Performance Optimization Strategies
Throttled Input Processing
Although the current components do not explicitly implement throttling, optimization can be achieved through the following methods:
// Recommended throttling implementation
import debounce from 'lodash/debounce'
const handleInputChange = debounce((value: string) => {
// Handle input change
}, 300)
Virtual Scrolling Option List
For scenarios with a large number of options, virtual scrolling can be considered:
// Virtual scrolling example structure
const VirtualSelect = defineComponent({
setup() {
const visibleOptions = ref([])
const scrollTop = ref(0)
const calculateVisibleOptions = () => {
// Calculate visible options logic
}
return () => (
<div
class="virtual-list"
onScroll={calculateVisibleOptions}
>
{visibleOptions.value.map(option => (
<Option {...option} />
))}
</div>
)
}
})
Component Caching Strategy
DyForm uses markRaw to avoid unnecessary reactive proxies:
const formItemElementMap: Record<string, any> = markRaw({
input: DyInput,
inputNumber: ElInputNumber,
// ... other components
})
Best Practices Guide
Form Reset Pattern
// DyForm reset method
const resetForm = () => {
if (!formRef.value) return false
formRef.value.resetFields()
}
// Manual reset example
const manualReset = () => {
formItemProps.value.forEach((item: FormItemPropType) => {
form.value[item.prop] = item.defaultValue
})
}
Default Value Filling Strategy
// Initialize form data
const initFormData = () => {
formItemProps.value.forEach((item: FormItemPropType) => {
form.value[item.prop] = form.value[item.prop] || item.defaultValue
})
active.value = formItemProps.value[0].name
}
Error Handling Pattern
// Validation error handling
const validateWithErrorHandling = async () => {
try {
await validate()
return true
} catch (error) {
ElMessage.error('表单验证失败,请检查输入')
return false
}
}
Troubleshooting
Common Issues and Solutions
1. Dynamic Form Components Not Rendering Correctly
Problem: The el field in JSON Schema does not match any registered component
Solution:
// Ensure components are correctly registered to formItemElementMap
const customWidgetMap = {
myCustomComponent: MyCustomComponent
}
// Use in DyForm
<DyForm
customWidgetMap={customWidgetMap}
formItemProps={schema}
/>
2. Selector Options Not Displaying
Problem: optionData or options property is empty
Solution:
// Ensure option data is correctly passed
<Select
optionData={computedOptions}
v-model={selectedValue}
/>
3. Date Range Validation Ineffective
Problem: Time range validation logic not executing correctly
Solution:
// Add custom validation rules
const customRules = [
{
validator: (rule, value, callback) => {
if (value.From && value.To && dayjs(value.From).isAfter(value.To)) {
callback(new Error('开始时间不能晚于结束时间'))
} else {
callback()
}
},
trigger: 'change'
}
]
Section Source
Summary
The form and selection component system of LMEs Web Base demonstrates best practices in modern front-end development. Through the JSON Schema-driven architecture of the DyForm dynamic form engine, the dual implementation strategy of the Select component system, and the reactive integration of DateTimePickRange, the system provides a complete form solution.
Key features include:
- Flexible Dynamic Form Rendering: Supports JSON Schema-driven rendering of multiple form control types
- Powerful Selector System: Provides both custom enhanced and Element Plus wrapper options
- Deep Reactive Integration: Fully utilizes Vue 3's reactive system features
- Internationalization Support: Complete multilingual environment adaptation
- Performance Optimization: Reasonable component caching and rendering strategies
This component system not only meets current business requirements but also lays a solid foundation for future feature expansion and performance optimization.