阿里开源Sifo之:可配置与高扩展性表单

时间:2021-1-8 作者:admin

上一篇文章对高扩展性、插件式前端开发框架—— sifo 进行了初步介绍,说明了其高扩展性的主要特点。高扩展性的其中一个方面是模型插件的高扩展性,下面将详细介绍一下官方最近发布的表单内核模型插件,及在 React 和 Vue 下,以 antd 和 antd-vue 为UI层的表单组件。

官方也提供了这两个场景的 codeSandbox 示例:antdantdv ,可以直接访问并修改代码体验。

这篇文章需要开发者事先了解 sifo 的基本使用方法,建议先看一下上一篇介绍文章,或查看快速上手示例:reactvue

antd 为UI层的效果

表单内核模型插件

  • 有什么功能

sifo-mplg-form-core(后面简称SifoFormCore)是一个不包含任何UI的表单处理内核,对表单字段进行统一的管理,并提供了一些表单操作 api(setValues/getValues/validate/addValidator等)。

sifo 是与UI框架和组件库完全解耦的,使用模型插件可以实现各式各样的功能,表单内核模型插件就是一个例子。

SifoFormCore 在 React 和 Vue 下都能使用,这样能保持使用方式一致。接入组件库作为UI层时只需要按组件库的事件约定处理即可,开发者也可以自己封装UI层,参照官方的antd、antdv方式。

SifoFormCore 可以使用 sifo 所有的扩展能力与特性,这是该表单与一般的组件库表单相比显著的特点。利用插件化和扩展能力,能很好地处理不同客户个性的、差异性的需求。

  • 如何使用
import SifoFormCore from '@schema-plugin-flow/sifo-mplg-form-core';
// sifo modelPlugin
{
  modelPlugin: {
    plugin: SifoFormCore,
    argsProvider: (mId, info) => {
      return {
        // 字段的key,无返回值认为不是字段
        fieldKey: (attr) => attr.props && attr.props.name,
        fieldChange: {
          // 表单字段change使用的handler
          changeHandler: (context, e) => {
            const { event, mApi } = context;
            let val = e;
            if (typeof e === "string" || typeof e === "number") {
              val = e;
            } else if (typeof e === "object") {
              val = e.target ? e.target.value : e;
            }
            mApi.setAttributes(event.key, { value: val }, true);
          },
          eventName: "change", // 组件库的值更新事件名
        },
      };
    },
  }
}
  • schema 格式

默认将 value, validators, rules, validateDisabled, validateInfo 等放在 attributes上,且 schema 节点 id 应与 fieldKey(此处指字段标识对应的值)一致。默认使用attributes.name作为字段标识。

{
  "id": "fieldKey01",
  "component": "Input",
  "attributes": {
    "name": "fieldKey01",
    "label": "字段名",
    "rules": [
      {
        "required": true,
        "message": "你需要填写fieldKey01",
        "trigger": [
          "pressEnter",
          "change"
        ]
      }
    ]
  }
}
  • 校验规则描述
    • 内置了必填、整数、最大最小值和长度校验;
    • 规则描述的message省略时将使用内置文案;
    • trigger省略时将使用类实例参数 fieldChange 的 eventName;
    • 调用validate、validateAll 时不区分 trigger;
{
  "rules": [
    {
      "required": true,
      "message": "请填写信息",
      "trigger": [
        "pressEnter",
        "change"
      ]
    },
    {
      "type": "integer"
    },
    {
      "max": 99.9
    },
    {
      "maxLength": 9
    }
  ]
}
  • 校验函数
    使用 mApi.addValidator 可以为指定字段追加校验函数,格式如下:
const validatorItem = {
  validator: (value, callback, opts:{ id, mApi, fieldKey }) => {
    // not passed
    callback({
    passed: false,
    status: 'error',
    message: 'invalidate message',
    });
    // passed
    callback();
  },
  trigger: ['eventName'], // 在何时触发,默认是类实例参数 fieldChange 的 eventName 
}
  • UI层封装

此模型插件只有表单内核,不包含任何UI部分,UI可按各自的情形封装。

  • 字段标识: 在字段节点时,在schema节点层和attributes层都将包含属性__isField__: true;

  • 默认将 value, validators, rules, validateDisabled, validateInfo 等放在 attributes 上;使用sifo-vue时,运行时这些属性在props上,定义时可直接放在schema的attributes上(sifo-vue内做了分类);

  • 可在模型插件 onComponentsWrap 生命周期中包装组件以进行 FormItem 的样式相关封装;

  • 可扩展、覆盖 mApi 方法来适配相应情形;

Ant-design 表单

表单主要是进行样式及校验信息展示的处理,开发者也可以通过formItemWrapper覆盖默认的处理方法。使用示例:

import SifoFormCore from '@schema-plugin-flow/sifo-mplg-form-core';
import AntdFormModelPlugin from "@schema-plugin-flow/sifo-mplg-form-antd";
// 样式: @import "~@schema-plugin-flow/sifo-mplg-form-antd/index.less";
// sifo plugins
[{
  modelPlugin: {
    plugin: SifoFormCore,
    argsProvider: (mId, info) => {
      return {
        // 字段的key,无返回值认为不是字段
        fieldKey: (attr) => attr.name,
        fieldChange: {
          // 表单字段change使用的handler
          changeHandler: (context, e) => {
            const { event, mApi } = context;
            // 可根据不同的组件进行值获取
            let val = e;
            if (typeof e === "string" || typeof e === "number") {
              val = e;
            } else if (typeof e === "object") {
              val = e.target ? e.target.value : e;
            }
            mApi.setAttributes(event.key, { value: val }, true);
          },
          eventName: "onChange", // antd的字段组件事件名是 onChange
        },
      };
    },
  }
},
{
  modelPlugin: AntdFormModelPlugin, // 要在SifoFormCore之后注册
},
{ pagePlugin, componentPlugin }
]

Ant-design-vue 表单

表单主要是进行样式及校验信息展示的处理,开发者也可以通过formItemWrapper覆盖默认的处理方法。使用示例:

import SifoFormCore from '@schema-plugin-flow/sifo-mplg-form-core';
import AntdVueFormModelPlugin from "@schema-plugin-flow/sifo-mplg-form-antdv";
// 样式: @import "~@schema-plugin-flow/sifo-mplg-form-antdv/index.less";
// sifo plugins
[{
  modelPlugin: {
    plugin: SifoFormCore,
    argsProvider: (mId, info) => {
      return {
        // 字段的key,无返回值认为不是字段;vue的一般属性都在props上,此处用 props.name 作为字段标识
        fieldKey: (attr) => attr.props && attr.props.name,
        fieldChange: {
          // 表单字段change使用的handler
          changeHandler: (context, e) => {
            const { event, mApi } = context;
            // 可根据不同的组件进行值获取
            let val = e;
            if (typeof e === "string" || typeof e === "number") {
              val = e;
            } else if (typeof e === "object") {
              val = e.target ? e.target.value : e;
            }
            mApi.setAttributes(event.key, { value: val }, true);
          },
          eventName: "change", // antd-vue的字段组件事件名是 change
        },
      };
    },
  }
},
{
  modelPlugin: AntdVueFormModelPlugin, // 要在SifoFormCore之后注册
},
{ pagePlugin, componentPlugin }
]

字段属性与逻辑处理

  • 字段FormItem属性

    schema中没有显式的FormItem层,其实是在UI层模型插件中提供的能力,如果需要还可以自定义其它能力。目前官方的UI层支持这些样式属性:

    • “class”: “test-subject”,
    • “itemClassName”: “subject-form-item”,
    • “labelCol”: {
      “span”: 8 },
    • “wrapperCol”: {
      “span”: 8,
      “offset”: 0 }
  • 组件插件

字段可以注册自己的插件来控制值更新事件及联动:

  subject: {
    onComponentInitial: (params) => {
      const { event, mApi } = params;
      mApi.addEventListener(event.key, 'change', (ctx, e) => {
      // 监听值更新事件并更改原始值
        mApi.setAttributes(event.key, {
          value: e.target.value + '修改值'
        });
      });
      // watch 属性变化并控制其它节点
      mApi.watch(event.key, (ctx, state, oldState) => {
        // 关联校验
        const val = mApi.getValue(event.key);
        mApi.disableValidate('typeDesc', val !== 'customized');
      });
    }
  },
  • 表单提交

一般使用如下方式:

submitBtn: {
  onComponentInitial: (params) => {
    const { event, mApi } = params;
    mApi.addEventListener(event.key, "click", (context) => {
      mApi.validateAll().then((e) => {
        if (e.passed) {
          const values = mApi.getValues();
          console.log("表单数据:", values);
          // post form data
        } else {
          console.error("表单校验未通过", e);
        }
      });
    });
  },
}

最后

官方后面计划提供更多组件库为UI层的表单组件,如Fusion/antd-mobile等,也会不断完善表单内置能力。热切欢迎大家提出宝贵的意见与建议、分享更多实用的模型插件和使用场景等。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。