in packages/vue/src/components/ReactiveField.ts [122:258]
setup(props: IReactiveFieldProps, { slots }) {
const formRef = useForm()
const parentRef = useField()
const optionsRef = inject(SchemaOptionsSymbol, ref(null))
let createField = () =>
formRef?.value?.[`create${props.fieldType}`]?.({
...props.fieldProps,
basePath: props.fieldProps?.basePath ?? parentRef.value?.address,
})
if (isVue2) {
createField = createFieldInVue2(createField)
}
const fieldRef = shallowRef(createField()) as Ref<GeneralField>
watch(
() => props.fieldProps,
() => (fieldRef.value = createField())
)
useAttach(fieldRef)
provide(FieldSymbol, fieldRef)
return () => {
const field = fieldRef.value
const options = optionsRef.value
if (!field) {
return slots.default?.()
}
if (field.display !== 'visible') {
return h('template', {}, {})
}
const mergedSlots = mergeSlots(field, slots, field.content)
const renderDecorator = (childNodes: any[]) => {
if (!field.decoratorType) {
return wrapFragment(childNodes)
}
const finalComponent =
FormPath.getIn(options?.components, field.decoratorType as string) ??
field.decoratorType
const componentAttrs = toJS(field.decorator[1]) || {}
const events: Record<string, any> = {}
each(componentAttrs, (value, eventKey) => {
const onEvent = eventKey.startsWith('on')
const atEvent = eventKey.startsWith('@')
if (!onEvent && !atEvent) return
if (onEvent) {
const eventName = `${eventKey[2].toLowerCase()}${eventKey.slice(3)}`
// '@xxx' has higher priority
events[eventName] = events[eventName] || value
} else if (atEvent) {
const eventName = eventKey.slice(1)
events[eventName] = value
delete componentAttrs[eventKey]
}
})
const componentData = {
attrs: componentAttrs,
style: componentAttrs?.style,
class: componentAttrs?.class,
on: events,
}
delete componentData.attrs.style
delete componentData.attrs.class
return h(finalComponent, componentData, {
default: () => childNodes,
})
}
const renderComponent = () => {
if (!field.componentType) return wrapFragment(mergedSlots?.default?.())
const component =
FormPath.getIn(options?.components, field.componentType as string) ??
field.componentType
const originData = toJS(field.component[1]) || {}
const events = {} as Record<string, any>
const originChange = originData['@change'] || originData['onChange']
const originFocus = originData['@focus'] || originData['onFocus']
const originBlur = originData['@blur'] || originData['onBlur']
each(originData, (value, eventKey) => {
const onEvent = eventKey.startsWith('on')
const atEvent = eventKey.startsWith('@')
if (!onEvent && !atEvent) return
if (onEvent) {
const eventName = `${eventKey[2].toLowerCase()}${eventKey.slice(3)}`
// '@xxx' has higher priority
events[eventName] = events[eventName] || value
} else if (atEvent) {
const eventName = eventKey.slice(1)
events[eventName] = value
delete originData[eventKey]
}
})
events.change = (...args: any[]) => {
if (!isVoidField(field)) field.onInput(...args)
originChange?.(...args)
}
events.focus = (...args: any[]) => {
if (!isVoidField(field)) field.onFocus(...args)
originFocus?.(...args)
}
events.blur = (...args: any[]) => {
if (!isVoidField(field)) field.onBlur(...args)
originBlur?.(...args)
}
const componentData = {
attrs: {
disabled: !isVoidField(field)
? field.pattern === 'disabled' || field.pattern === 'readPretty'
: undefined,
readOnly: !isVoidField(field)
? field.pattern === 'readOnly'
: undefined,
...originData,
value: !isVoidField(field) ? field.value : undefined,
},
style: originData?.style,
class: originData?.class,
on: events,
}
delete componentData.attrs.style
delete componentData.attrs.class
return h(component, componentData, mergedSlots)
}
return renderDecorator([renderComponent()])
}
},