Appearance
return
jsx
return () => {
if (!checkWidgetId(props.formProps.widget, 'form')) {
console.error('表单必须以AForm组件开始');
return null;
}
const { bucket, ...someElse } = props.formProps;
const vNodeData = someElse;
const { AForm } = FormComps;
return (
<AForm ref={formRef} class="general-form" model={formData} {...vNodeData}>
{createEle(bucket)}
</AForm>
);
};
formData
js
const formData = reactive({});
watch(
() => props.formData,
(n) => {
if (n && typeof n === 'object') {
for (const key in n) {
if (n.key?.text) {
formData[key] = n[key].text;
}
}
}
},
{ deep: true }
);
formData:
json
{[alias]: value}
createEle
js
const createEle = (bucket): VNodeChild | null => {
if (!returnBucketType(bucket)) return null;
let res: VNodeChild | null = [];
if (returnBucketType(bucket) === 'Object') {
res.push(formItemCtor(bucket));
} else if (returnBucketType(bucket) === 'Array') {
for (let i = 0, length = bucket.length; i < length; i++) {
if (!bucket[i] || !bucket[i].widget) continue;
res.push(formItemCtor(bucket[i]));
}
} else res = null;
return res;
};
判断 bucket 的类型,然后根据类型返回对应的 VNode
formItemCtor
js
const formItemCtor = (itemConf) => {
if (itemConf.textContent) return `${itemConf.textContent}`;
if (!itemConf.widget) return null;
if (itemConf.widget.toLowerCase() === 'slot') return outerItemCtor(itemConf);
return innerItemCtor(itemConf);
};
textContent 保留字段 根据 widget 的类型,返回对应的 VNode
slot => outerItemCtor
其他 => innerItemCtor
outerItemCtor
js
const outerItemCtor = (itemConf): VNodeChild | null => {
const k = !!itemConf && itemConf.alias ? itemConf.alias : 'default';
const _slots = extendSlots(slots);
return _slots[k] ? _slots[k]() : null;
};
返回 name 为 alias 的插槽
> _slots: 组件插槽对象; 数据来源: higherOrderForm 组件中的 template 的 name 默认 name = 'default'
Tips: vue jsx 中 slot 是函数
innerItemCtor
js
const innerItemCtor = (itemConf): VNodeChild | null => {
const {
widget,
alias,
rules,
formatter,
bucket,
id,
class: customClass,
style,
...rest
} = itemConf
if (hidden || props.formData?.[alias]?.hidden) return null
const _props = getPropsFromConf(widget, rest)
const vNodeData = {
key: alias,
id,
class: customClass,
style,
..._props,
formatter: getFormatterFormConfig(formatter),
...eventsComposition(widget, alias),
}
{/* <AInput alias="xxx" key="xxx" onSelect="xxx" /> */}
if (alias) vNodeData.ref = `${alias}Ref`
if (VNODEDATA_VALUE_PROP_LIST_OF_WIDGETS.includes(widget)) vNodeData.value = formData?.[alias]
if (VNODEDATA_CHECKED_PROP_LIST_OF_WIDGETS.includes(widget))
vNodeData.checked = formData?.[alias]
const res = getRulesFromConfig(mergeRules(rules, props.rulesConfig?.[itemConf.name]), widget)
if (res[0]) {
vNodeData.rules = res[1]
}
if (bucket) {
return h(
resolveComponent(widget as string) as ConcreteComponent,
{ ...vNodeData },
{ default: () => createEle(bucket) }
)
}
return h(resolveComponent(widget), { ...vNodeData })
}
解构值:rest 是原子组件相关的配置,如 label、title、placeholder 等;
getPropsFromConf() 过滤无效定义的属性和原子组件不支持的属性;
getFormatterFormConfig:
js
export function getFormatterFormConfig(
formatter: string
): (val: string) => string {
return allFormatter[formatter];
}
方法定义在/util/formatter.js 中 通过 allFormatter 获取对应的 formatter 函数;
args: formatter 自定义的 formatter 函数名;
- mergeRules
js
export function mergeRules(rule1, rule2) {
if (rule1 && rule2) {
return merge(rule1, rule2);
}
return rule2 ?? rule1;
}
合并自定义的 rule;
- getRulesFromConfig:
js
export function getRulesFromConfig(ruleObject: RuleObject, widget: string) {
if (widget !== 'AFormItem') return [false, null];
return [true, ruleObject];
}
过滤,只有 widget 为 AFormItem 时,返回 true 和 ruleObject;可参考
在配置中自定义的 rule 或者在 props 的 ruleConfig 中定义的 rule, key 为 alias 的值;
- eventsComposition
js
const getEventsComposition = (widget, name, formDataItem) => {
const confirmedWidget = allAPI.find(
(item) =>
item.widget === widget || !!~item.widget.indexOf(kebabCase(widget))
);
if (!confirmedWidget) return {};
const res: { [k: string]: (args: any) => void } = {};
confirmedWidget.emits.forEach((item) => {
if (!item) return;
res[item] = function (args) {
eventsExtraHandler(item, formDataItem, args);
if (
!(
widget !== 'ASelect' &&
(item === 'onMouseenter' || item === 'onMouseleave')
)
)
emit(replaceOn(item), name, args);
};
});
return res;
};
- args: widget, alias, formDataItem
widget: 原子组件名称
alias: 配置项中自定义的别名
初始化 formData[alias]对应的值 = {text: *}- 函数解释:
通过原子组件名称获取到原子组件中的事件列表,然后遍历事件列表,将事件列表中的事件名作为 key,将事件处理函数作为 value,当原子组件触发相应的事件时,执行对应的事件处理函数
>>emit(replaceOn(item), name, args)
replaceOn => 给原事件名称加自定义前缀 @gener-; 如原事件名称为 onClick,则替换为 @gener-click
name = alias; 这个传递给高阶组件用于事件拦截,
args 原事件函数的参数