JSON Schema&表单UI快速生成解析

这篇具有很好参考价值的文章主要介绍了JSON Schema&表单UI快速生成解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、JSON Schema

​ JSON(JavaScript Object Notation)是一种轻量&常见的数据交换格式,基本的数据的结构就是key-value,具有易于生成和解析的优点,通过JSON可以灵活地表达程序所需要的数据结构。

​ 但JSON本身并没有特定的规范(本身结构也不支持注释),所以对于数据本身的描述是缺失的,比如说开发人员或者程序,就无法判断下面这份数据里面的age为string是否是符合预期的类型。

{
  "name": "John Doe",
  "mobile": "1370000001",
  "age": "30"
}

​ JSON Schema定义了一套能够较为完整地来描述JSON的规范,基于JSON Schema的规范去描述我们所需要的数据结构,或者基于这种规范去开发程序,就能实现预期效果。

使用场景:

1. 数据校验

​ 可能是JSON Schema最常见的场景,无论是前端还是后台都有校验数据的需求,表单校验,CI/CD的自动化测试等等。

以上面的JSON为例,如果要规定age为number,并且必须小于等于20,那么可以这样声明一份JSON Schema

{
  "$schema": "http://json-schema.org/schema",
  "title": "Person",
  "description": "an example",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "mobile": {
      "type": "string"
    },
    "age": {
      "type": "number",
      "maximum": 20
    },
  }
}

​ 那么当age为string,或者为number,但不在范围内的时候都会提示校验失败

JSON Schema&表单UI快速生成解析

​ 简单的校验示例:https://www.jsonschemavalidator.net/s/rrRbDzHF

应用

Ajv.js

​ 一个基于JSON Schema的校验库,常用于nodejs、浏览器、微信小程序等场景的数据校验,通过声明一个JSON Schema来快速验证数据,而无需进行代码开发。

示例:

const Ajv = require('ajv');
const ajv = new Ajv();
// schema
const schema = {
  $schema: 'http://json-schema.org/schema',
  ...
};
const validate = ajv.compile(schema);
// 验证的数据
const validData = {
  ...
  age: '30',
};
const validResult = validate(validData);
if (validResult) {
  // 验证通过
  console.log('pass');
} else {
  // 验证不通过
  console.log(validate.errors);
  // [
  //   {
  //     keyword: 'type',
  //     dataPath: '.age',
  //     schemaPath: '#/properties/age/type',
  //     params: { type: 'number' },
  //     message: 'should be number'
  //   }
  // ]
}

​ 不只是JavaScript/Typescript,其他编程语言也有基于JSON Schema实现的校验器,如Java的Snow 、go的gojsonschema和Python的jschon 等等都是基于此去开发的。所以通过JSON Schema规范,还可以保持前后端校验的一致。

2. form自动生成

​ JSON Schem虽然有规范约束,但仍然还是一份描述数据的JSON配置,那么基于这份配置,逻辑上就能自动渲染出功能完整的表单UI。

应用
  1. vue-json-schema-form:基于 vue.js 和JSON Schema 渲染form,最新版本已经支持Vue3

  2. form-render:基于react.js的表单解决方案,最新版本使用Ant Design作为视觉主题

  3. formily:跨端能力,逻辑可跨框架,主要模块(react.js+antd为例):

    @formily/core:实现状态管理、表单校验等逻辑,和UI无关

    @formily/react:实现交互效果,视图桥接

    @formily/antd:扩展组件库,开箱即用的表单UI

​ 以上表单渲染库都有提供对应的表单设计器,可以通过拖拽的形式快速生成JSON Schema,整体流程如下:

JSON Schema&表单UI快速生成解析

​ 如何选择合适的库?如是基于react.js的low code项目,那其实form-render就已经足够了。formily虽然支持的场景很多,但有一定的接入成本(从官方文档就能看出),而且包的体积也相对较大。如form-render,只需要引入form-render,然后正确传入props就能直接渲染出预期的UI。

​ 常见的在低代码平台中,都会有表单模块,但这部分的逻辑通常并不是整个低代码项目的核心,那就可以交由form-render这类表单渲染库去做,基于此就能减少开发单独维护表单映射或者校验的代码。当然也有可能需要开发部分定制的widgets,以适配于较为复杂或者更切合业务的情况。

二、form-render

​ from-render整体可以分为core和widgets。core实现了表单映射、校验和监听等等,widgets就是一些UI组件实现了。

core

映射

widgets包含了内置组件和扩展组件,内置的组件已经提供,基本包含在这里:https://x-render.gitee.io/generator/playground。同时还支持由开发者自定义一些扩展组件,提供props.widgets传入自定义的object就能把扩展form组件注册到widgets映射表内。

// form-render-core/src/index.js
<ConfigProvider locale={zhCN} {...configProvider}>
	<FRCore widgets={{ ...defaultWidgets, ...widgets }} {...rest} />
</ConfigProvider>

​ 如果要覆盖默认组件,可以使用mapping注册到form映射表内

  // form-render-core/src/index.js
  const tools = useMemo(
    () => ({
      widgets,
      mapping: { ...defaultMapping, ...mapping },
  ...

​ 需要注意的是这里只是form映射表,同时还需要将自定义的widgets注册到表内。无论是内置或者扩展的组件都会,只要实现了一个基于映射表的getWidgetName方法就能获取到需要映射的组件名,渲染出对应的UI。

// form-render-core/src/core/RenderField/ExtendedWidget.js
// JSON Schema指定widget
let widgetName = getWidgetName(schema, mapping);
const customName = schema.widget || schema['ui:widget']; 
if (customName && widgets[customName]) {
  widgetName = customName;
}
const readOnlyName = schema.readOnlyWidget || 'html'; // 指定readOnly模式下的widget,或者使用默认html
if (readOnly && !isObjType(schema) && !isListType(schema)) {
  // 基础组件的readOnly会默认使用readOnlyName
  widgetName = readOnlyName;
}
if (!widgetName) {
  widgetName = 'input';
  return <ErrorSchema schema={schema} />;
}
const Widget = widgets[widgetName];
const extraSchema = extraSchemaList[widgetName];
...
// form-render-core/src/core/RenderField/index.js
// 单属性UI最基础的内容
const RenderField = props => {
	...
  return (
    <>
      {_showTitle && titleElement}
      <div
        className={`${contentClass} ${hideTitle ? 'fr-content-no-title' : ''}`}
        style={contentStyle}
      >
        {/* Widget渲染 */}
        <ExtendedWidget {...widgetProps} />
        {/* 说明信息 */}
        <Extra {...widgetProps} />
        {/* ErrorMessage,校验相关 */}
        <ErrorMessage {...messageProps} />
      </div>
    </>
  );
}
校验

​ 需要实现两个基础的校验方法,validateSingle(单属性校验)和validateAll(表单校验),具体的校验逻辑可以通过一些开源工具去实现,如form-render使用的是async-validator作为校验工具,async-validator是一个表单异步校验的工具,Ajv.js也可以异步校验,只需要初始化的时候带上schema内带上{$async: true}

Ajv.js async-validator
server 支持 支持
client 支持 支持
同步校验 支持 不支持
异步校验 支持 支持
package size 119.6 kb 14.2kb

​ 多数情况下的表单校验都会选择异步执行,所以包括form-render这类表单渲染库,或者一些开源组件库(如element)会使用async-validator作为校验工具。

// form-render-core/src/core/RenderField/index.js
const validateSingle = (data, schema = {}, path, options = {}) => {
	...
  /**
   * getDescriptorSimple会转换成匹配async-validator的数据结构,如果是其他的校验工具,可能就是另一种转换了
   * 以path为key,rules为value,和result的[path]: data是对应的
   */
  const descriptor = getDescriptorSimple(schema, path);
  let validator;
  try {
    // 校验
    validator = new Validator(descriptor);
  } catch (error) {
    return Promise.resolve();
  }
  // 错误提示的模板 type number string
  let messageFeed = locale === 'en' ? en : cn;
  merge(messageFeed, validateMessages);
  validator.messages(messageFeed);
  return validator
    .validate({ [path]: data })
    .then(res => {
      return [{ field: path, message: null }];
    })
    .catch(({ errors, fields }) => {
    	// 
      return errors;
    });
};

​ validateAll只需要基于validateSingle遍历完成校验即可。validateSingle除了作为validateAll的一部分,同时也会在validateField中使用,为单个属性实时校验使用。

  const onChange = value => {
    // 节流、表单方法等
    ...
    validateField({
      path: dataPath, // 路径
      formData: formDataRef.current, // 表单数据
      flatten, // schema 的转换结构,[path]: {parent, children, schema}
      options: {
        locale,
        validateMessages,
      },
    })
    ...
  };

​ 只是有校验是不够的,最重要的是同时要提示数据校验不通过的原因,所以还需要实现message动态模板,以及ErrorMessage组件承载错误提示。如form-render,实现了validateMessageCN.js作为message模板,ErrorMessage.js作为错误提示组件。

监听

​ 数据监听常见于低代码的场景中,预期是希望用户输入对应的属性后,能实时在渲染器响应,同步渲染UI。form-render提供了watch属性,用于数据的监听的唤起回调。

// form-render-core/src/Watcher.js
	...
  /**
   * formData当前表单的数据,watchKey被监听的key
   * getValueByPath主要是处理#和普通的key
   * 如果是#,返回的就是formData
 
   */
  const value = getValueByPath(formData, watchKey);
  // callback
  const watchObj = watch[watchKey];

  useEffect(() => {
    const runWatcher = () => {
      if (typeof watchObj === 'function') {
        try {
          // 执行回调函数,并把value传递到外层
          watchObj(value);
        } catch (error) {
          console.log(`${watchKey}对应的watch函数执行报错:`, error);
        }
      } else if (watchObj && typeof watchObj.handler === 'function') {
        try {
          // 适配多个参数的情况,其实目前的话,主要是handler和immediate
          watchObj.handler(value);
        } catch (error) {
          console.log(`${watchKey}对应的watch函数执行报错:`, error);
        }
      }
    };

    if (firstMount) {
      const immediate = watchObj && watchObj.immediate;
      if (immediate) {
        // 如果immediate为true,会在首次加载的时候触发一次watch
        runWatcher();
      }
    } else {
      runWatcher();
    }
  ...

​ 需要注意的是,存在对象或者数组嵌套的情况,getValueByPath也需要有根据path来获取value的能力。如form-render是通过lodash-es模块的get方法来实现的。

​ 通过watch映射表构建多个watch实例。

...
{
  {/* watchList = Object.keys(watch) */}
  watchList.length > 0
  ? watchList.map((item, idx) => {
    	{/* null */}
      return (
        <Watcher
          key={idx.toString()}
          watchKey={item}
          watch={watch}
          formData={formData}
          firstMount={firstMount}
        />
      );
    })
  : null
}
...

widgets

​ widgets主要是包含了内置组件,部分组件是直接使用了组件库提供的组件,如TextArea、InputNumber等,这些组件只需要调整下样式就能直接用于表单渲染了;但大部分组件都是经过封装后再使用的,如Slider、Color和Date组件等,不同的组件封装的逻辑不同,比如Slider包含了组件库的Slider和InputNumber,并对schema做解构,构建成对应的props。

form-render自定义组件:input, checkbox, checkboxes, color, date, time, dateRange, timeRange, imageInput, url, list, map, multiSelect, radio, select, slider, switch, upload, html, rate

form-render组件库组件:number, textarea, treeSelect文章来源地址https://www.toymoban.com/news/detail-404791.html

到了这里,关于JSON Schema&表单UI快速生成解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • hive中get_json_object函数不支持解析json中文key

    今天在 Hive 中 get_json_object 函数解析 json 串的时候,发现函数不支持解析 json 中文 key。 例如: 我们希望的结果是得到姓名对应的值 张三 ,而运行之后的结果为 NULL 值。 我们希望的结果是得到姓名对应的值 张三 ,而运行之后的结果为 18 。 是什么原因导致的呢?我们查看

    2024年02月12日
    浏览(56)
  • element-ui for循环生成表单时,表单校验问题

    1、静态生成的表单,校验规则是放在data中处理 2、动态表单页面,需要把规则放在el-form-item中,进行校验 注意事项: 当使用v-for循环生成表单时, :prop有格式要求 格式不对会报错 :prop=“‘appraisalTempContent.’ + index + ‘.score’” 字段说明: 1、appraisalTempContent=遍历数组的k

    2024年02月16日
    浏览(46)
  • Json Schema简介和Json Schema的.net实现库 LateApexEarlySpeed.Json.Schema

    Json schema是一种声明式语言,它可以用来标识Json的结构,数据类型和数据的具体限制,它提供了描述期望Json结构的标准化方法。 利用Json Schema, 你可以定义Json结构的各种规则,以便确定Json数据在各个子系统中交互传输时保持兼容和一致的格式。 一般来说,系统可以自己实现

    2024年02月04日
    浏览(39)
  • Json Schema简介和Json Schema的高性能.net实现库 LateApexEarlySpeed.Json.Schema

    Json schema是一种声明式语言,它可以用来标识Json的结构,数据类型和数据的具体限制,它提供了描述期望Json结构的标准化方法。 利用Json Schema, 你可以定义Json结构的各种规则,以便确定Json数据在各个子系统中交互传输时保持兼容和一致的格式。 一般来说,系统可以自己实现

    2024年02月04日
    浏览(36)
  • Element-UI可以动态生成的form表单

    此form表单每一项绑定的值组成一个对象,对象叠加组成了一个对象数组,循环对象数组生成form的表单项。当点击新增一项时,其实就是给form表单对象数组添加一个对象,删除则反之。值得注意的是,由于动态表单得到的是一个对象数组,但我们需要的是表单的值组成的对象

    2024年02月11日
    浏览(52)
  • 【项目部署】JavaScript解析JSON解析报错Unexpected token xxx is not valid JSON

    这个报错发生在之前部署的一个前后端分离的项目中。后端使用的Spring Boot,前端使用的JavaScript,前后端交互使用Thymeleaf框架。 项目组的另一个小伙伴说,突然有个页面打不开了,整个页面全空白。我F12打开浏览器发现有如下报错: 首先我打开了JavaScript的代码部分,发现报

    2024年02月07日
    浏览(53)
  • vue + element-ui 循环生成指定form表单

    最近遇到一个需要超级写超级多字段的表单,初略计算大概四十来个吧字段吧,/(ㄒoㄒ)/~~,这也太麻烦了,想了想能不能简单封装一下,找到了个巨人,嗯哼,就踩一下吧 参考文章: Vue3.0 根据JSON对象生成指定form表单 上面文章是vue3的,逻辑都一样。以下是vue2 我的写法 注

    2024年02月11日
    浏览(56)
  • Lottie--前端动画效果--UI输出json格式--lottie动画在JavaScript中使用

    Lottie一个适用于Web、Android、iOS、React Native和Window的移动库,它可以使用Bodymovin解析以json格式导出的Adobe After Effects动画,并再移动设备上进行本地渲染。 1.需要引入JavaScript文件,我使用的是cdn中的链接。这里直接上链接,按需取用。点这里 2.json格式的文件 我不是UI啊,我也

    2023年04月09日
    浏览(51)
  • Python中如何快速解析JSON对象数组

    由于浏览器可以迅速地解析JSON对象,它们有助于在客户端和服务器之间传输数据。本文将描述如何使用Python的JSON模块来传输和接收JSON数据。 JSON (JavaScript Object Notation)是一种用于数据交换的语法,它对人的读写很简单,对计算机的解析和生产也很简单,而且还可以存储数据。

    2024年02月10日
    浏览(50)
  • mORMot2 生成和解析 JSON

    本文非完全原创,本文部分内容来自博客园,作者:{咏南中间件} 前综合示例 ,整个示例是建立在mORMot特有的实现模式的基础上,非常用的序列化反序列化,但又有别于字符串拼接,据说效率极高。 基础 下面是最基本的方法,如何定位!这里用到了 GetValueByPath 函数。 进阶

    2024年04月25日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包