【EasyPage 教你写表单10】- 字段继承

10 阅读3分钟

字段继承

在表单开发中,我们会经常遇到这样的一个场景:

  • 我想要之前的字段 A,但是又对它有一些调整。

此时,我们的做法可能是:

  • 将差异的点抽象成:Props,在组件使用的地方,根据不同的场景传递不同的 Props。

但这样有个问题:

  • 我们影响了原有的字段 A,那两个使用场景都需要回测。
  • 我们需要做额外的抽象工作,增加开发成本。
  • 抽象不一定完美,可能后续还会有所调整。

EasyPage 中,我们可通过:nodeUtil.extends 完美解决上述场景。一个字段,可变化的内容:

  • 副作用
  • 显隐逻辑
  • 默认值、label、tooltip 等文案
  • 组件 Props
  • 数据处理
  • 验证逻辑

我们的这个:nodeUtil.extends 包含了上述所有变化。

示例

在之前的例子中,我们继承过年龄字段,我们先来定义一个非常完整的年龄字段:

  • 字段 ID: 'age'; 字段 Label: '年龄';字段默认值:'';字段必填:是。
  • 字段提交时,处理成 number 类型,提交的 key 为:age
  • 字段增加校验:如未填写,则提示:“请输入年龄”;和 name 字段联动,当:name=pk 时,年龄可超过 200 岁,否则不可。
  • 字段的 placeholder 根据:name 的值而变化。
  • 当字段 name=a 时,不展示年龄字段。
  • 当字段 age < 10 岁时,增加提示语:“儿童”
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Empty, InputEffectedType, nodeUtil } from '@easy-page/antd-ui';
import React from 'react';

export const age = nodeUtil.createField<
  string,
  { name: string },
  Empty,
  InputEffectedType
>(
  'age',
  '年龄',
  {
    /** 默认值 */
    value: '',
    /** 必填 * 号 */
    required: true,
    /** 数据预处理 */
    postprocess(context) {
      return {
        age: Number(context.value),
      };
    },
    /** 字段验证 */
    validate({ value, pageState }) {
      if (!value) {
        return { success: false, errorMsg: '请输入年龄' };
      }
      if (+value < 0 || (+value > 200 && pageState.name !== 'pk')) {
        return { success: false, errorMsg: '请输入合法年龄' };
      }
      return { success: true };
    },
    /** 字段副作用 */
    actions: [
      {
        effectedKeys: ['name'],
        /** 加载时,立即执行 */
        initRun: true,
        action: ({ effectedData }) => {
          return {
            effectResult: {
              inputProps: {
                placeholder: `${effectedData.name || '-'} 的年龄`,
              },
            },
          };
        },
      },
    ],
    /** 字段显示与隐藏 */
    when: {
      effectedKeys: ['name'],
      show({ effectedData }) {
        return effectedData.name !== 'a';
      },
    },
  },
  {
    /** 输入框配置 */
    input: { trigger: 'onChange' },
    /** FormItem 配置 */
    formItem: {
      /** 自定义提示语:带上下文 */
      customExtra: ({ value }) => {
        return <div>{value && +value < 10 ? '儿童' : ''}</div>;
      },
    },
  }
);

我们看一下效果:

见:easy-page.github.io/easy-page-d…

继承

基于上述的演示,我们来继承并替换掉这个年龄:

  • 字段 ID: 'age'; 字段 Label: '我的年龄';字段必填:否。
  • 验证时,允许为空
  • 年龄字段永远展示。
  • 给年龄字段增加一个问号提示文案
import { nodeUtil } from '@easy-page/antd-ui';
import { age } from './age';

export const newAge = nodeUtil.extends(age, {
  name: '我的年龄',
  required: false,
  validate(oldValidate) {
    return (options) => {
      if (!options.value) {
        return { success: true };
      }
      return oldValidate?.(options);
    };
  },
  when(oldWhen) {
    return {
      effectedKeys: oldWhen?.effectedKeys || [],
      show(context) {
        return true;
      },
    };
  },
  /** 更改组件配置 **/
  fieldUIConfig: (oldConfig) => {
    const newConfig = { ...(oldConfig || {}) };
    newConfig.formItem = newConfig.formItem || {};
    newConfig.formItem.tooltip = '这是新的年龄';
    return newConfig;
  },
});

基于上述示例,我们通过:extends 扩展出自身所需要的新的年龄,而且对原有 age 无任何影响。 针对原有字段的属性:

  • name、id、required 等属性直接变化即可。
  • 对于函数类型属性,则都提供了:oldXxx 来决定如何执行。

如:

  validate(oldValidate) {
    return (options) => {
      if (!options.value) {
        return { success: true };
      }
      return oldValidate?.(options);
    };
  },

返回了一个新的验证函数。

我们开看看效果:

见:easy-page.github.io/easy-page-d…