为了快速做外包,我做了一个低代码表单生成器

3,884 阅读3分钟

前言

做前端的几年间,陆续接过几个外包,基本都是不需要ui设计的表单页面。虽然开发起来不难但也繁琐,所以想做一个工具能减少部分重复的工作。
介绍文档
使用地址

简介

基于 antd 的低代码表单生成器,旨在快速搭建简单的表单应用场景。

设计模式

image.png

表单模式

image.png

服务

我使用了axios进行接口请求,配置时可以自定义axios拦截器并预览请求结果。 image.png

事件

事件分为表单事件和组件事件,目前仅有一些常用的事件,后续有需求会慢慢添加。支持设置防抖节流、串联功能,串联是指需要等待当前事件执行完成后再往下执行后续事件。

image.png

本地部署

使用地址中点击下载按钮可以下载一个表单模板,根据介绍文档设置schema即可部署到服务器。
也可以作为组件在本地使用,添加自定义组件应对一些复杂场景。

环境准备

确保正确安装 Node.js 且版本为 18+ 。

安装依赖

yarn add @roddan/form-editor

代码编写

表单设计模式代码如下:

import React, { useRef } from 'react';
import {
  FormEditor,
  Material,
  Settings,
  FormCanvas,
} from '@roddan/form-editor';

const Editor = () => {
  const ref = useRef();
  return (
    <FormEditor
      mode="design"
      ref={ref}
      // 预览打开的url和保存回调
      actionProp={{
        // 预览url
        previewUrl: `xxxxx`,
        // 保存按钮回调
        onSave(schema) {
          console.log('schema');
          console.log(schema);
        },
        // 下载按钮回调不传不展示按钮
        download(schema) {
          console.log('schema');
          console.log(schema);
        },
      }}
    >
      <Material />
      <FormCanvas />
      <Settings />
    </FormEditor>
  );
};
export default Editor;

设置页点击保存按钮后会将 schema 存在 localstorage 中,预览页会从中取。

预览模式其实就是最终要拿到的表单页。

import React from 'react';
import { FormEditor, FormCanvas } from '@roddan/form-editor';

const Editor = () => {
  const ref = useRef();
  return (
    <FormEditor
      mode="form"
      // 这里不传会从localstorage中取
      defaultValue={schema}
    >
      <FormCanvas />
    </FormEditor>
  );
};
export default Editor;

自定义组件

自定义组件参数及类型如下:

interface IDragElementProp {
  type: string;     // 组件类型
  render: FC<any>;  // 表单渲染组件
  setting: FC<any>; // 属性设置组件
  text: string;     // 组件库文案
  Icon: ReactNode;  // 组件库icon
  eventActions: EEventAction[];  // 支持的事件列表
  initialData: Partial<IBaseElement>; // 初始默认值
}

以颜色选择器为例,配置事件-值变化同步其他组件,属性可设置弹框位置placement

import React from 'react';
import { SettingItem, SettingWrap, useRegisterEvents, EEventAction, useFormUpdate } from '@roddan/form-editor';
import type { IBaseElement, TElementRender, TElementSetting } from '@roddan/form-editor';
import { ColorPicker, Select } from 'antd';

const RenderContent: TElementRender = ({
  element,
  fieldValue = '',
  customStyle, // 自定义css
  setFieldValue,
}) => {
  const { placement } = element;
  const { eventFunctions } = useRegisterEvents(element);

  // 监听值发生变化的hook
  useFormUpdate(() => {
    eventFunctions[EEventAction.VALUE_CHANGE]?.(fieldValue);
  }, [fieldValue]);

  return (
    <ColorPicker
      value={fieldValue}
      onChange={(v) => {
        setFieldValue(v.toHexString());
      }}
      placement={placement}
      style={{ ...customStyle }}
    />
  );
};

const SettingContent: TElementSetting = ({ element, setElementProp }) => {
  const { placement } = element;
  return (
    <SettingWrap title="元素设置">
      <SettingItem label="弹窗位置">
        <Select
          options={['left', 'right'].map((item) => ({
            label: item,
            value: item,
          }))}
          value={placement}
          onChange={(val) => {
            setElementProp('placement', val);
          }}
        />
      </SettingItem>
    </SettingWrap>
  );
};

const Icon = <div>icon-</div>;

const eventActions = [EEventAction.VALUE_CHANGE];

const initialData: Partial<IBaseElement> = {
  elementName: '颜色选择器',
  gridSpan: 3,
  gridLayout: false,
  placement: 'left',
};

const type = 'custom';

export const customElement = {
  type,
  render: RenderContent,
  setting: SettingContent,
  Icon,
  text: '测试颜色组件121231231',
  eventActions,
  initialData,
};

在FormEditor组件上传入即可。

import React from 'react';
import { FormEditor, FormCanvas } from '@roddan/form-editor';
import { customElement } from './customEl';

const Comp = () => {
  return (
    <FormEditor
      mode="design"
      customElements={[customElement]}
    >
      <FormCanvas />
    </FormEditor>
  );
};

export default Comp;

image.png

image.png