Skip to main content
Version: Next

Form and Selection Components

Table of Contents​

  1. Introduction
  2. Project Structure Overview
  3. DyForm Dynamic Form Engine
  4. Select Component System
  5. Date Time Picker
  6. Performance Optimization Strategies
  7. Best Practices Guide
  8. Troubleshooting
  9. 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.