上篇简要介绍了formilyjs以及基于其构建了表单设计器,实现了表单动静设计曾经预览性能,本片将介绍表单设计器的一些高级配置,使其能更好的使用于咱们的节点编辑以及连线编辑。

designable高级配置

申请及自定义数据注入

一般来说,咱们页面的申请都是对立封装好的,在应用时咱们如何把咱们封装好的申请或者曾经有的数据源注入到咱们的
表单设计器中呢:
SchemaField 组件是专门用于解析JSON-Schema动静渲染表单的组件,在应用createSchemaField时咱们能够传入scope来注入到全局作用域中链接:

import { FC, Ref, useEffect, useImperativeHandle, useState } from 'react';import { Modal } from 'antd';import {  FormItem,  Input,  Form,  Submit,  ArrayBase,  ArrayCards,  ArrayCollapse,  ArrayItems,  ArrayTable,  ArrayTabs,  BaseItem,  Cascader,  Checkbox,  DatePicker,  Editable,  FormButtonGroup,  FormCollapse,  FormGrid,  FormTab,  GridColumn,  NumberPicker,  Password,  PreviewText,  Radio,  Reset,  Select,  SelectTable,  Space,  Switch,  TimePicker,  Transfer,  TreeSelect,  Upload,} from '@formily/antd';import api from '@/api';import { createSchemaField } from '@formily/react';import { LgetItem } from '@/utils/storage';import { createForm } from '@formily/core';interface PreviewProps {  previewRef: Ref<{ setVisible: (flag: boolean) => void }>;  modalConfig: { [key: string]: any };}const SchemaField = createSchemaField({  components: {    Input,    ArrayBase,    ArrayCards,    ArrayCollapse,    ArrayItems,    ArrayTable,    ArrayTabs,    BaseItem,    Cascader,    Checkbox,    DatePicker,    Editable,    Form,    FormButtonGroup,    FormCollapse,    FormGrid,    FormItem,    FormTab,    GridColumn,    NumberPicker,    Password,    PreviewText,    Radio,    Reset,    Select,    SelectTable,    Space,    Submit,    Switch,    TimePicker,    Transfer,    TreeSelect,    Upload,  },  scope: {    $fetch: api,    selectList: [{ label: 'aaa', value: 'aaa' }, { label: 'bbb', value: 'bbb' }]  }});const Preview: FC<PreviewProps> = ({ previewRef, modalConfig }) => {  const [visible, setVisible] = useState(false);  useImperativeHandle(previewRef, () => ({    setVisible,  }));  const [params, setParams] = useState({});  const normalForm = createForm({});  useEffect(() => {    if (modalConfig && visible) {      const playgroundList = LgetItem('playgroundList') || [];      const data = playgroundList.find((s) => s.id === modalConfig.id);      setParams(data?.params || {});    }  }, [modalConfig, visible]);  const handleCancel = () => {    setVisible(false);  };  return (    <Modal      title="模板预览"      visible={visible}      onCancel={handleCancel}      footer={null}    >      <Form form={normalForm} onAutoSubmit={console.log} {...params.form}>        <SchemaField schema={params.schema} />        <Submit block>保留</Submit>      </Form>    </Modal>  );};export default Preview;

在应用表单设计器时,便能够应用注入的scope值,比方咱们筹备一个json,抉择一个下拉控件,配置相应器,而后通过咱们注入的申请获取这个json,展现对应的下拉值:

 $effect(() => {        $self.loading = true        $fetch({            url: '/getSelectList',            method: 'get',            params: {}        }).then(res => {            $self.loading = false            // 当返回值不是label和value时转化一下            $self.dataSource = res.map(s => ({ label: res.name, value: res.id }))        }).catch(() => {            $self.loading = false        })    }, [])

这里的$fetch就是咱们注入的申请了

表单配置

  1. form提交的key为字段标识,可自定义批改,默认为随机字符串
  2. 题目为form表单的label
  3. 反对自定义搜寻的,比方select,须要在组件属性下筛选器中配置表单式,能力反对label搜寻

    (inputValue, option) => {    return option.label.indexOf(inputValue) !== -1;}

  4. 如果配置了响应器规定中和内部一样的配置,比方组件属性,那么响应器规定中的会笼罩内部的配置(内部的组件属性生效)

高级配置

高级配置在响应器规定中,这里次要针对于一些一般配置无奈实现的性能进行阐明,比方常见的联动,动静取值等场景进行阐明。

  • $self为以后选中的表单对象
  • $form为form对象
  • $deps为依赖对象(需在上方依赖字段配置起源字段)
  • $observable申明一个可察看对象
  • $effect和react的useEffect应用相似
  • $values为提交的form表单对象
  1. 动静枚举值,如果咱们有一个select控件,这个控件的值是接口返回的

    $effect(() => {    $self.loading = true    $fetch({        url: '/getSelectList',        method: 'get',        params: {}    }).then(res => {        $self.loading = false        // 当返回值不是label和value时转化一下        $self.dataSource = res.map(s => ({ label: res.name, value: res.id }))    }).catch(() => {        $self.loading = false    })}, [])
  2. 联动变动枚举值,比方咱们有两个select,第一个select是mechanism机构,第一个select是user人员,咱们抉择一个机构后,第二个select会依据第一个select的值来从接口中获取机构下的人员列表,这是一个比拟常见的联动抉择性能,那么放在表单设计器外面咱们该如何实现呢(实现形式不惟一,这里提供思路)。

    // 第一个select,咱们监听mechanism的变动,flag次要利用为跳过首次渲染(保障反显失常展现),当mechanism改版(即手动选值)后,清空user的取值。$effect(() => {    $self.loading = true    $fetch({        url: '/getMechanismList',        method: 'get',        params: {}    }).then(res => {        $self.loading = false        // 当返回值不是label和value时转化一下        $self.dataSource = res.map(s => ({ label: res.name, value: res.id }))    }).catch(() => {        $self.loading = false    })}, [])const state = $observable({ flag: false });$effect(() => {    if (state.flag) {        $form.reset('user');    }    state.flag = true;}, [$self.value])

    mechanism变动时,清空user列表,发动申请获取user列表

        $effect(() => {        $self.dataSource = []        if ($deps.mechanism) {            $self.loading = true                $fetch({                url: '/getSelectList',                method: 'get',                params: {                    mechanism: $deps.mechanism                }            }).then(res => {                $self.loading = false                // 当返回值不是label和value时转化一下                $self.dataSource = res.map(s => ({ label: res.name, value: res.id }))            }).catch(() => {                $self.loading = false            })        }    }, [$deps.mechanism])

小试牛刀

咱们应用mock数据简略做一个联动

// mock/api.tsexport default {  'GET /api/mechanism': [    {      value: '1',      label: '机构1',    },    {      value: '2',      label: '机构2',    },  ],  'GET /api/users': (req, res) => {    // 增加跨域申请头    const query: any = req.query;    const user: any = {      '1': [        {          value: '1-1',          label: '机构1-人员1',        },        {          value: '1-2',          label: '机构1-人员2',        },      ],      '2': [        {          value: '2-1',          label: '机构2-人员1',        },        {          value: '2-2',          label: '机构2-人员2',        },      ],    };    res.send(user[query.id]);  },};

咱们定义了两mock接口,mechanismusers,前者返回一个机构列表,后者依据前者的id返回对应的列表,接着咱们在上一期中的预览弹窗中注入申请,这里咱们间接应用umi提供的request

// Preview.tsximport { request } from 'umi';...const SchemaField = createSchemaField({  components: ...,  scope: {    $fetch: request,  },});

最初咱们在表单设计中增加申请

// mechanism$effect(() => {  $self.loading = true  $fetch("/api/mechanism", {})    .then((res) => {      $self.loading = false      // 当返回值不是label和value时转化一下      $self.dataSource = res    })    .catch(() => {      $self.loading = false    })}, [])// users$effect(() => {  $self.dataSource = []  if ($deps.mechanism) {    $self.loading = true    $fetch("/api/users", {      params: {        id: $deps.mechanism,      },    })      .then((res) => {        $self.loading = false        // 当返回值不是label和value时转化一下        $self.dataSource = res      })      .catch(() => {        $self.loading = false      })  }}, [$deps.mechanism])

最初再到表单模板预览一下:

好了,本篇介绍的性能都实现了,那么下一篇咱们将把流程可是化的编辑性能和咱们的表单模板进行关联起来,批改表单模板就能批改节点或连线的属性编辑,达到真正的动静属性编辑成果,纵情期待。

本文地址:链接
本文github地址:链接
github demo地址:链接