Skip to content
On this page

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 原事件函数的参数