Chendi WuMediaProjectsBlog
Back to blog

前端架构

前端架构笔记:整体架构思考,低代码引擎(lowcode-engine)与组件物料化。

2023-02-07
NotesArchitecture

前端架构

学技术不能过于专精,需要横向理解,向广度挖掘。

原则

设计原则:架构服务于业务,以提升业务开发效率和体验为目标,配合业务发展齐头并进。 业务原则:稳定性、组织架构配合和成本控制等因素。

业务与架构契合:架构演进能给让业务开发更内聚、协作更顺畅,最终带来业务开发效率和体验带来提升。 成本可控:架构设计不建议憋大招,而应该是一定时间跨度内可落地、可完成的。架构设计应该是可以拆分为多次小的架构演进,然后通过配合业务持续迭代,最终达成设计目标。

架构搭建关注方向

  • 模块 / 组件划分、分层的策略和维度;
  • 模块 / 组件间通信方案;
  • 架构演进中遇到的问题;
  • 架构演进过程中使用的工具;
  • 防劣化机制;
  • 架构演进和业务迭代的合作模式;
  • 架构演进的方向

设计考虑

虽然像高并发、负载均衡和容灾等架构设计的核心点在移动端上不存在,但是移动端还是有它自身的重点:

  • 组件化:移动端往往是多个团队合力完成同一个 App 的开发工作,为了实现多团队协作,会将 App 拆分为不同的模块,由不同的团队负责不同模块的开发维护工作。同时模块会被构建为中间产物,以组件的形式进行集成,从而加速整体工程的编译速度。使得整体架构方向都在以组件化为承载形式,同时不断缩小业务所需要关心的范围、不断扩大代码复用范围;
  • 插件化:随着业务的持续迭代,App 中聚合的功能越来越多,包体积也越变越大,导致用户下载安装体验变差。所以业界也衍生了插件化方案,可以将安装包拆分为宿主和若干插件。用户在应用商店下载时只下载安装宿主部分,其他插件在用户使用到相关功能时再通过网络进行下载,从而解决包大小问题;
  • 多 App 复用:业界很多产品在原有 App 的基础上都有衍生出极速版、特价版、或者专业版,通过不同的 App 来服务不同的用户群体。而这些不同的新衍生的 App 和原 App 在很多功能上都是重合的,如果分开开发维护的话,显然需要投入更多的人力资源。所以往往都会考虑实现多 App 复用,使得相同的部分只用进行一次开发,从而提升研发效率;
  • 动态化:大多数业务中都会有一些业务层级较深、使用用户较少,或者一些周期较短、时效性很强的业务功能(比如节假日活动等)。这些业务功能如果使用原生的开发方式,需要重新发版,时间点和覆盖率可能无法保障,同时也会导致包 size 增大。所以往往会采用动态化的方式进行开发:比如 H5 网页、Hybrid、RN、小程序等,这样可以实现相应功能的快速迭代,而不需要重新发版
  • 多端复用:前面提到了在 Android 或者 iOS 某一平台上的多 App 复用,也提到了动态化能力,往往动态化就是具备同一套代码在 Android 和 iOS 双端实现复用,这样可以极大的提升研发效率。当然除了动态化方案,一些原生方案也可以实现在 Android 和 iOS 双端复用,同时 Flutter 等自建渲染方案可以实现在更多端复用,这也是业界在重点关注的一个方向。

完善与优化

架构优化还是性能优化,都是长周期、持续推进的过程,所以我们也会围绕业务环境去做完善。

  • 多端复用:字节内部的信息流产品有今日头条和今日头条极速版两个产品,现在两个产品的代码复用率还可以做进一步的提升,这是后续架构优化的一个重要发力点。这样可以实现更高的开发效率,使得这两个产品可以更加快速的给用户提供更多优质服务。
  • 架构优化闭环:头条架构一直在持续优化和演进,解决了大量的业务和技术问题。但现阶段的业务和技术问题发现到架构优化还没有完全形成闭环,还有很多问题没有被挖掘出来,问题的解决程度也无法全面评估。后续会从架构度量指标、架构分析工具建设和防劣化机制 3 个方向着力实现架构优化闭环。
    • 架构度量指标:有了架构度量指标后,就可以主动对现有业务和架构进行分析,快速去发现和定位问题,从而进行相应的优化。同时也可以对优化后的结果进行度量,判断问题是否得到了有效解决;
    • 架构分析工具:头条在进行架构优化的过程中,往往需要进行大量的分析来发现问题、定位问题和解决问题,而相应的工具能够极大的提高效率。后续会针对性的建设更多的架构分析工具,更好的服务架构演进和业务发展;
    • 防劣化机制:由于业务的高速迭代和新同学的加入等原因,头条日常开发过程中也遇到了很多不符合架构设计的代码,这些代码会导致架构出现劣化,缩短架构生命周期。后续会建立更多的防劣化机制,及时发现并拦截这些不合理代码,保障架构能持续正向演进。
  • 技术输出:对外输出了大量的技术方案,这一块将会继续加大投入,沉淀和输出更多更优的技术方案,为业界前端技术生态的发展做出贡献。

架构设计注意

技术人还是应该多看看业务,不能只在技术的象牙塔里,同时还要多看看业界的动向,接触业界的专家和经验。

  • 全局视角和思维:以全局的视角和思维去发现和审视业务的需求和问题,从而设计出最适合业务的架构;
  • 架构配合业务同步发展:
    • 架构演进是为了解决业务问题、提升研发质量。因而需要深入业务,了解业务痛点;
    • 好的架构是要不断演变去适应业务的发展,其源于不停地衍变而非一成不变的设计;
    • 架构演进过程中,要做好架构演进和业务迭代的协同工作;
  • 做好防劣化机制: 任何架构都有生命周期,所以会有源源不断的新的架构被设计和演进出来; 没有防劣化机制的话,填坑速度可能永远赶不上挖坑速度。而恰当的防劣化机制,能够延长架构的生命周期,使得架构师可以更关注于新增问题。

image.png

lowcode-engine / vue

🚀 Projects

Since the lowcode-engine official website is built on the React ecosystem, it has been refactored to the Vue ecosystem.

Below, the package usage is provided:

Lowcode
  • git: https://github.com/cdLab996/lowcode-engine-demo-vue
  • online
    • Vue 3: https://lowcode-engine-demo-vue.vercel.app/
    • Vue 2.7: https://lowcode-engine-demo-vue2-7.vercel.app/
    • Vue 2.7 Examples: https://lowcode-engine-demo-vue2-7-examples.vercel.app/
🏗️ Main
PackageDescriptionLatest
@cdlab996/lowcode-hooks2.7🏗️ Hooks for renderer/simulatornpm version
@cdlab996/lowcode-utils2.7🏗️ Utility methods for renderer/simulatornpm version
@cdlab996/lowcode-vue-renderer2.7🏗️ Lowcode renderer using Vue2.7 frameworknpm version
@cdlab996/lowcode-vue-simulator-renderer2.7🏗️ Lowcode simulator renderer using Vue2.7 enginenpm version
🧩 Plugins & Extensions
PackageDescriptionLatest
@cdlab996/lowcode-engine-ext-vue🕹️ Adapt lowcode-engine-ext to the Vue version.npm version
@cdlab996/plugin-directive-loading🧩 Vue directive v-loadingnpm version
@cdlab996/lowcode-plugin-manual🧩 lowcode product user manualnpm version
@cdlab996/lowcode-plugin-set-doc-url🧩 Component material new documentation addressnpm version
@cdlab996/lowcode-plugin-vue-code-editor2.7🧩 lowcode CodeEditor for Vue 2.7 (Not available yet)npm version
🔨 Tools
PackageDescriptionLatest
@cdlab996/vite-plugin-lib-types2.7🔨 Generate typescript declarations, Supports Vue2.7 Filesnpm version
@cdlab996/create-lowcode2.7🔨 Scaffold tool for initializing Lowcode projectsnpm version
@cdlab996/vue-cli-plugin-lowcode2.7🔨 Development and build tool plugin for Lowcode enginenpm version
🎨 Materials
PackageDescriptionLatest
@cdlab996/element-plus-lowcode-materials🎨 Element Plus(2.6.3) Materials for Vue3npm version
@cdlab996/antd-lowcode-materials🎨 Ant Design Vue(4.1.2) Materials for Vue3npm version
@cdlab996/vant-lowcode-materials🎨 Vant(4.8.10) Materials for Vue3npm version
@cdlab996/element-lowcode-materials2.7🎨 Element(2.15.13) Materials for Vue2.7npm version
@cdlab996/antd-lowcode-materials2.7🎨 Ant Design Vue(1.7.8) Materials for Vue2.7npm version
@cdlab996/vant-lowcode-materials2.7🎨 Vant(2.12.54) Materials for Vue2.7npm version

lowcode-engine / 组件转物料

基础组件转物料信息整理说明

背景说明

为了能够在低代码平台运行使用我们的基础组件,需要把基础组件转换成低代码平台可识别的组件,也就是物料。物料需要进行一定的配置和处理,这个过程中,需要一份配置文件,也就是资产包(就是一份json)。资产包文件中,针对每个物料定义了它们在低代码编辑器中的使用描述。

如何引入组件

我们需要在资产包里定义这个包的获取方式,如果不定义,就不会被低代码引擎动态加载并对应上组件实例。定义方式是 UMD 的包,低代码引擎会尝试在 window 上寻找对应 library 的实例;

定义低代码编辑器中加载的资源列表,包含公共库和组件(库) cdn 资源等;

字段字段描述字段类型规范等级备注
packages[].id?资源唯一标识StringA资源唯一标识,如果为空,则以 package 为唯一标识
packages[].title?资源标题StringA资源标题
packages[].packagenpm 包名StringA组件资源唯一标识
packages[].versionnpm 包版本号StringA组件资源版本号
packages[].type资源包类型StringAA取值为: proCode(源码)、lowCode(低代码,默认为 proCode
packages[].schema低代码组件 schema 内容objectAA取值为: proCode(源码)、lowCode(低代码)
packages[].deps当前资源包的依赖资源的唯一标识列表ArrayA唯一标识为 id 或者 package 对应的值
packages[].library作为全局变量引用时的名称,用来定义全局变量名StringA低代码引擎通过该字段获取组件实例
packages[].editUrls组件编辑态视图打包后的 CDN url 列表,包含 js 和 cssArrayA低代码引擎编辑器会加载这些 url
packages[].urls组件渲染态视图打包后的 CDN url 列表,包含 js 和 cssArrayAA低代码引擎渲染模块会加载这些 url
packages[].advancedEditUrls组件多个编辑态视图打包后的 CDN url 列表集合,包含 js 和 cssObjectAAA上层平台根据特定标识提取某个编辑态的资源,低代码引擎编辑器会加载这些资源,优先级高于 packages[].editUrls
packages[].advancedUrls组件多个端的渲染态视图打包后的 CDN url 列表集合,包含 js 和 cssObjectAAA上层平台根据特定标识提取某个渲染态的资源, 低代码引擎渲染模块会加载这些资源,优先级高于 packages[].urls
packages[].external当前资源在作为其他资源的依赖,在其他依赖打包时时是否被排除了(同 webpack 中 external 概念)BooleanAAA某些资源会被单独提取出来,是其他依赖的前置依赖,根据这个字段决定是否提前加载该资源
packages[].loadEnv指定当前资源加载的环境ArrayAAA主要用于指定 external 资源加载的环境,取值为 design(设计态)、runtime(预览态)中的一个或多个
packages[].exportSourceId标识当前 package 内容是从哪个 package 导出来的StringAAA此时 urls 无效
packages[].exportSourceLibrary标识当前 package 是从 window 上的哪个属性导出来的StringAAAexportSourceId 的优先级高于exportSourceLibrary ,此时 urls 无效
packages[].async标识当前 package 资源加载在 window.library 上的是否是一个异步对象BooleanAasync 为 true 时,需要通过 await 才能拿到真正内容
packages[].exportMode标识当前 package 从其他 package 的导出方式StringA目前只支持 "functionCall", exportMode等于 "functionCall" 时,当前package 的内容以函数的方式从其他 package 中导出,具体导出接口如: (library: string, packageName: string, isRuntime?: boolean) => any

示例:

"packages": [
    {
      "package": "element-ui",
      "version": "2.5.12",
      "urls": [
        "https://unpkg.com/element-ui/lib/index.js",
        "https://unpkg.com/element-ui/lib/theme-chalk/index.css"
      ],
      "library": "ELEMENT"
    },
    {
      "package": "vant",
      "version": "2.12.53",
      "urls": [
        "https://unpkg.com/vant@2.12/lib/vant.min.js",
        "https://unpkg.com/vant@2.12/lib/index.css"
      ],
      "library": "vant"
    }
  ],

如何定义组件

单个组件描述内容为 json 结构,主要包含以下三部分内容,分别为:

  • 基础信息 (A): 描述组件的基础信息,通常包含包信息、组件名称、标题、描述等。
  • 组件属性信息 (A): 描述组件属性信息,通常包含参数、说明、类型、默认值 4 项内容。
  • 能力配置/体验增强: 推荐用于优化搭建产品编辑体验,定制编辑能力的配置信息。

整体结构概览:http://lowcode-engine.cn/doc?url=sde3wf

基础信息 ElRow示例:

{
  "category": "基础组件",
  "componentName": "ElRow",
  "npm": {
    "package": "element-ui",
    "version": "2.30.6",
    "exportName": "Row",
    "destructuring": true
  }
}

基础信息 字段说明

字段字段描述字段类型允许空
componentName组件名称String否
title组件中文名称String否
description组件描述String是
docUrl组件文档链接String否
screenshot组件快照String否
icon组件的小图标String (URL)是
tags组件标签String是
keywords组件关键词,用于搜索联想String是
devMode组件研发模式String  (proCode,lowCode)是
npmnpm 源引入完整描述对象Object否
npm.package源码组件库名String否
npm.exportName源码组件名称String否
npm.subName子组件名String否
npm.destructuring解构Bool否
npm.main组件路径String否
npm.version源码组件版本号String否
snippets内容为组件不同状态下的低代码 schema (可以有多个), 用户从组件面板拖入组件到设计器时会向页面 schema 中插入 snippets中定义的组件低代码 schemaObject[]否
group用于描述当前组件位于组件面板的哪个 tabString否
category用于描述组件位于组件面板同一 tab 的哪个区域String否
priority用于描述组件在同一 category 中的排序String否

组件属性信息 ElRow 示例:

"props": [
    {
      "name": "gutter",
      "propType": "number"
    },
    {
      "name": "type",
      "propType": "string",
      "defaultValue": "flex"
    },
    {
      "name": "justify",
      "propType": {
        "type": "oneOf",
        "value": ["start", "end", "center", "space-around", "space-between"]
      },
      "defaultValue": "start"
    },
    {
      "name": "align",
      "propType": {
        "type": "oneOf",
        "value": ["top", "middle", "bottom"]
      }
    },
    {
      "name": "tag",
      "propType": "string",
      "defaultValue": "div"
    }
]
组件属性信息 props

描述组件属性信息,通常包含名称、类型、描述、默认值 4 项内容。

字段字段描述字段类型允许空
name属性名称String否
propType属性类型String/Object否
description属性描述String是
defaultValue属性默认值Any是

经验:描述可改为用 title: {label:'',tip:''}

存在基本类型和复合类型,描述如下:Prop — Vue.js

基本类型
propType 值类型描述PropType 类型
'array'数组类型Array
'bool'布尔类型Boolean
'func'函数类型Function
'number'数字类型Number
'object'对象类型Object
'string'字符串类型String
'node'节点类型定义具名插槽
'any'任意值类型会生成多个setter切换,如:node、string、object、array类型
复合类型
能力配置/体验增强 configure

configure ElRow 示例:

"configure": {
    "supports": {
      "events": ["click", "change"],
      "loop": true,
      "condition": true,
      "style": true
    },
    "component": {
      "isContainer": true,
      "isLayout": true
    },
    "props": [
      {
        "type": "group",
        "title": "布局样式",
        "display": "block",
        "items": [
          {
            "type": "field",
            "title": "类型",
            "name": "type",
            "defaultValue": "flex",
            "condition": false
          },
          {
            "type": "field",
            "title": "栅格间隔",
            "name": "gutter",
            "setter": "NumberSetter"
          },
          {
            "type": "field",
            "title": "水平排列",
            "name": "justify",
            "setter": {
              "componentName": "SelectSetter",
              "defaultValue": "start",
              "props": {
                "options": [
                  { "title": "start", "value": "start" },
                  { "title": "end", "value": "end" },
                  { "title": "center", "value": "center" },
                  { "title": "space-around", "value": "space-around" },
                  { "title": "space-between", "value": "space-between" }
                ]
              }
            }
          },
          {
            "type": "field",
            "title": "垂直排列",
            "name": "align",
            "setter": {
              "componentName": "SelectSetter",
              "defaultValue": "start",
              "props": {
                "options": [
                  { "title": "top", "value": "top" },
                  { "title": "middle", "value": "middle" },
                  { "title": "bottom", "value": "bottom" }
                ]
              }
            }
          }
        ]
      }
    ]
  }
基础字段
字段字段描述字段类型备注
props (A)属性面板配置Array用于属性面板能力描述
component(A)组件能力配置Object与组件相关的能力、约束、行为等描述,有些信息可从组件视图实例上直接获取
supports (AA)通用扩展配置能力支持性Object用于通用扩展面板能力描述
advanced (AAA)高级特性配置Object用户可以在这些配置通过引擎上下文控制组件在设计器中的表现,例如自动初始化组件的子组件、截获组件的操作事件进行个性化处理等
属性面板配置 props

根据属性值类型 propType,确定对应控件类型 (setter) ,详见https://lowcode-engine.cn/site/docs/guide/appendix/setters

configure下的props还可以是对象的形式,与组件属性信息props并存

优先使用组件下的props,当不能满足用户体验时,需用configure来扩展

坑点:设置ArraySetter类型时,不要定义type:filed, 不然会导致面板数据改变后视图不同步。isRequired 属性配置快捷编辑项。

extraProps示例标签demo:

const getValue = function (target, fieldValue) {
  const map = target.getNode().children.map((child) => {
    const primaryKey = child.getPropValue('primaryKey')
      ? String(child.getPropValue('primaryKey'))
      : child.id
    return {
      primaryKey: primaryKey,
      title: child.getPropValue('title'),
    }
  })
  return map
}

const setValue = function (target, value) {
  const node = target.getNode()

  const map = {}
  if (!Array.isArray(value)) {
    value = []
  }
  value.forEach((item) => {
    const tabitem = Object.assign({}, item)
    map[item.primaryKey] = tabitem
  })
  node.children.mergeChildren(
    (child) => {
      const primaryKey = String(child.getPropValue('primaryKey'))
      if (Object.hasOwnProperty.call(map, primaryKey)) {
        child.setPropValue('title', map[primaryKey].title)
        delete map[primaryKey]
        return false
      }
      return true
    },
    () => {
      const items = []
      for (const primaryKey in map) {
        if (Object.hasOwnProperty.call(map, primaryKey)) {
          items.push({
            componentName: 'van-tab',
            props: map[primaryKey],
          })
        }
      }
      return items
    },
    (child1, child2) => {
      const a = value.findIndex(
        (item) => String(item.primaryKey) === String(child1.getPropValue('primaryKey'))
      )
      const b = value.findIndex(
        (item) => String(item.primaryKey) === String(child2.getPropValue('primaryKey'))
      )
      return a - b
    }
  )
}

API说明:https://lowcode-engine.cn/site/docs/api/project#mergechildren

通用扩展面板支持性配置 supports

样式配置面板能力描述,描述是否支持行业样式编辑、是否支持类名设置等。

{
  "configure": {
    // 支持的事件枚举
    "supports": {
      // 支持事件列表
      "events": ["click", "change"],
      // 支持循环设置
      "loop": true,
      // 支持条件设置
      "condition": true,
      // 支持样式设置
      "style": true
    }
  }
}
组件能力配置 component

特别说明: 当默认插槽和其他具名插槽是互斥的情况下,需要显示的定义default, 且isContainer 属性需设为false

描述举例:

{
  configure: {
    component: {
      // 组件是否是容器组件(可拖入,类似于插槽)
      isContainer: true,
      isModal: false,
      descriptor: 'title',
      nestingRule: {
        childWhitelist: ['SelectOption'],
        parentWhitelist: ['Select', 'Table'],
      },
      rootSelector: '.next-dialog',
      disableBehaviors: ['copy', 'remove'],
      actions: {
        name: 'copy', // string;
        content: '+', // string | ReactNode | ActionContentObject;
        items: [], // ComponentAction[];
        condition: 'always', // boolean | ((currentNode: any) => boolean) | 'always';
        important: true, // boolean;
      },
    },
  },
}
高级功能配置 advanced
字段用途类型备注
initialChildren组件拖入“设计器”时根据此配置自动生成 children 节点 schemaNodeData[]/Function NodeData[]((target: SettingTarget) => NodeData[]);
getResizingHandlers用于配置设计器中组件 resize 操作工具的样式和内容Function(currentNode: any) => Array<{ type: 'N'
callbacks配置 callbacks 可捕获引擎抛出的一些事件,例如 onNodeAdd、onResize 等Callback-
callbacks.onNodeAdd在容器中拖入组件时触发的事件回调Function(e: MouseEvent, currentNode: any) => any
callbacks.onNodeRemove在容器中删除组件时触发的事件回调Function(e: MouseEvent, currentNode: any) => any
callbacks.onResize调整容器尺寸时触发的事件回调,常常与 getResizingHandlers搭配使用Function详见 Types 定义
callbacks.onResizeStart调整容器尺寸开始时触发的事件回调,常常与 getResizingHandlers搭配使用Function详见 Types 定义
callbacks.onResizeEnd调整容器尺寸结束时触发的事件回调,常常与 getResizingHandlers搭配使用Function详见 Types 定义
callbacks.onSubtreeModified容器节点结构树发生变化时触发的回调Function(currentNode: any, options: any) => void;
callbacks.onMouseDownHook鼠标按下操作回调Function(e: MouseEvent, currentNode: any) => any;
callbacks.onClickHook鼠标单击操作回调Function(e: MouseEvent, currentNode: any) => any;
callbacks.onDblClickHook鼠标双击操作回调Function(e: MouseEvent, currentNode: any) => any;
callbacks.onMoveHook节点被拖动回调Function(currentNode: any) => boolean;
callbacks.onHoverHook节点被 hover 回调Function(currentNode: any) => boolean;
callbacks.onChildMoveHook容器节点的子节点被拖动回调Function(childNode: any, currentNode: any) => boolean;

描述举例:

{
  configure: {
    advanced: {
      callbacks: {
        onNodeAdd: (dragment, currentNode) => {
          const layoutPNode = currentNode.document.createNode({
            componentName: "WsCard",
            title: "卡片组件",
            props: { },
            children: [dragment.schema],
          });
          setTimeout(() => {
            if (!currentNode.getChildren().has(dragment)) {
              return;
            }
            const newNode = currentNode.document.createNode(
              Object.assign(layoutPNode.schema)
            );
            currentNode.insertBefore(newNode, dragment, false);
            dragment.remove(false);
            newNode.getChildren().get(0).select();
          }, 1);
        }
      },
      getResizingHandlers: () => {
        return [ 'E' ];
      },
      initials: [
        {
          name: 'linkType',
          initial: () => 'link'
        },
      ]
    },
  }
}

开发规范

目录结构

引入的第三方库vant、element和wshoto的组件库,需在public下的lib下以库名建立文件夹,文件名为 index 。示例:

物料资产

一个UI 组件库对应一个json文件,方便管理。示例:

组件定义规范

宗旨: 以低代码平台用户体验为优先级,而不是物料书写方便

  1. description 字段描述定义清晰,需用中文,描述文字过长时需定义成 title 字段
"title": {
  "label": "自定义搜索逻辑",
  "tip": "第一个参数是节点node,第二个参数是搜索关键词keyword,通过返回布尔值表示是否命中"
},
  1. defaultValue 默认值字段 按需在 componentsList 下的 props 上定义默认值
"componentList": [
  {
    "title": "WSHOTO_PC 组件",
    "children": [
      {
        "componentName": "WeShineExportButton",
        "library": "WSHOTO_PC_UI",
        "snippets": [
          {
            "screenshot": "https://helios-allpublic-1257616148.cos.ap-shanghai.myqcloud.com/img/input.png",
            "title": "导出列表",
            "schema": {
              "componentName": "WeShineExportButton",
              "props": {
                "moduleId": "demo",
                "moduleFileName": "导出列表文件",
                "btnText": "导出列表",
                "getParams": {
                  "type": "JSFunction",
                  "value": "function getParams() {\n          return {};\n        }"
                },
                "createFn": {
                  "type": "JSFunction",
                  "value": "function createFn(data) {\n       return { url: '/v3/base-auditlog/api/audit/log/download/jobId', method: 'post', data};\n        }"
                },
                "getProgressFn": {
                  "type": "JSFunction",
                  "value": "function getProgressFn(options) {\n       return { url: '/v3/base-auditlog/api/audit/log/download/progress', method: 'get',  params: {...options}}; \n        }"
                },
                "getUrlFn": {
                  "type": "JSFunction",
                  "value": "function getProgressFn(options) {\n       return { url: '/v3/base-auditlog/api/audit/log/download/file', method: 'get',  params: {...options}}; \n        }"
                }
              }
            }
          }
        ]
      }
    ]
  }
]
  1. propType 需严格定义类型
  • 可枚举的字符串类型需定义成 oneOf 枚举值类型,而不能定义成 string
{
  "name": "justify",
  "propType": {
    "type": "oneOf",
    "value": ["start", "end", "center", "space-around", "space-between"]
  }
}
  • 可同时存在多个类型时,需用 oneOfType 的复合类型定义出来
{
  "name": "v-model",
  "description": "绑定的值",
  "propType": {
    "type": "oneOfType",
    "value": [
      "string",
      "bool",
      "number"
    ]
  }
},
  • 对象类型需定义成 shape 或 exact 复合类型
"propType": {
    "type": "shape",
    "value": [
      {
        "name": "span",
        "description": "span",
        "propType": "number"
      },
      {
        "name": "offset",
        "description": "offset",
        "propType": "number"
      }
    ]
},
  • 当props的值为颜色值时,需使用 ColorSetter
{
  "name": "inactive-color",
  "title": "关闭时的背景色",
  "setter": "ColorSetter"
}

完整demo示例

Element row和col组件
{
  "version": "0.0.1",
  "components": [
    {
      "category": "基础组件",
      "componentName": "ElRow",
      "npm": {
        "package": "element-ui",
        "version": "2.30.6",
        "exportName": "Row",
        "destructuring": true
      },
      "props": [
        {
          "name": "gutter",
          "propType": "number"
        },
        {
          "name": "type",
          "propType": "string",
          "defaultValue": "flex"
        },
        {
          "name": "justify",
          "propType": {
            "type": "oneOf",
            "value": ["start", "end", "center", "space-around", "space-between"]
          },
          "defaultValue": "start"
        },
        {
          "name": "align",
          "propType": {
            "type": "oneOf",
            "value": ["top", "middle", "bottom"]
          }
        },
        {
          "name": "tag",
          "propType": "string",
          "defaultValue": "div"
        }
      ],
      "configure": {
        "supports": {
          "loop": true,
          "condition": true,
          "style": true
        },
        "component": {
          "isContainer": true,
          "isLayout": true
        },
        "props": [
          {
            "type": "group",
            "title": "布局样式",
            "display": "block",
            "items": [
              {
                "type": "field",
                "title": "类型",
                "name": "type",
                "defaultValue": "flex",
                "condition": false
              },
              {
                "type": "field",
                "title": "栅格间隔",
                "name": "gutter",
                "setter": "NumberSetter"
              },
              {
                "type": "field",
                "title": "水平排列",
                "name": "justify",
                "setter": {
                  "componentName": "SelectSetter",
                  "defaultValue": "start",
                  "props": {
                    "options": [
                      {
                        "title": "start",
                        "value": "start"
                      },
                      {
                        "title": "end",
                        "value": "end"
                      },
                      {
                        "title": "center",
                        "value": "center"
                      },
                      {
                        "title": "space-around",
                        "value": "space-around"
                      },
                      {
                        "title": "space-between",
                        "value": "space-between"
                      }
                    ]
                  }
                }
              },
              {
                "type": "field",
                "title": "垂直排列",
                "name": "align",
                "setter": {
                  "componentName": "SelectSetter",
                  "defaultValue": "start",
                  "props": {
                    "options": [
                      {
                        "title": "top",
                        "value": "top"
                      },
                      {
                        "title": "middle",
                        "value": "middle"
                      },
                      {
                        "title": "bottom",
                        "value": "bottom"
                      }
                    ]
                  }
                }
              }
            ]
          }
        ]
      }
    },
    {
      "category": "基础组件",
      "componentName": "ElCol",
      "npm": {
        "package": "element-ui",
        "version": "2.30.6",
        "exportName": "Col",
        "destructuring": true
      },
      "configure": {
        "supports": {
          "loop": true,
          "condition": true,
          "style": true
        },
        "component": {
          "isContainer": true,
          "isLayout": true,
          "nestingRule": {
            "descendantBlacklist": ["ElCol"],
            "parentWhitelist": ["ElRow"]
          }
        },
        "props": [
          {
            "type": "group",
            "title": "布局样式",
            "display": "block",
            "items": [
              {
                "type": "field",
                "title": "占据列宽",
                "name": "span",
                "setter": "NumberSetter"
              },
              {
                "type": "field",
                "title": "左侧间隔",
                "name": "offset",
                "setter": "NumberSetter"
              },
              {
                "type": "field",
                "title": "向右移动",
                "name": "push",
                "setter": "NumberSetter"
              },
              {
                "type": "field",
                "title": "向左移动",
                "name": "pull",
                "setter": "NumberSetter"
              }
            ]
          }
        ]
      }
    }
  ],
  "componentList": [
    {
      "title": "布局组件",
      "children": [
        {
          "componentName": "ElRow",
          "library": "element-ui",
          "snippets": [
            {
              "screenshot": "https://helios-allpublic-1257616148.cos.ap-shanghai.myqcloud.com/img/card.png",
              "title": "栅格-行",
              "schema": {
                "componentName": "ElRow",
                "children": []
              }
            }
          ]
        }
      ]
    },
    {
      "title": "布局组件",
      "children": [
        {
          "componentName": "ElCol",
          "library": "element-ui",
          "snippets": [
            {
              "screenshot": "https://helios-allpublic-1257616148.cos.ap-shanghai.myqcloud.com/img/card.png",
              "title": "栅格-列",
              "schema": {
                "componentName": "ElCol",
                "children": []
              }
            }
          ]
        }
      ]
    }
  ]
}
Vant grid和gridItem组件
{
  "version": "0.0.1",
  "components": [
    {
      "category": "基础组件",
      "componentName": "van-grid",
      "npm": {
        "package": "vant",
        "version": "2.12.53",
        "exportName": "Grid",
        "destructuring": true
      },
      "props": [
        {
          "name": "column-num",
          "title": "列数",
          "propType": "number",
          "defaultValue": "4"
        },
        {
          "name": "gutter",
          "title": "格子间隔",
          "propType": "number",
          "defaultValue": "0"
        },
        {
          "name": "direction",
          "title": "排列方向",
          "propType": {
            "type": "oneOf",
            "value": ["vertical", "horizontal"]
          },
          "defaultValue": "vertical"
        },
        {
          "name": "border",
          "propType": "bool",
          "title": "显示边框",
          "defaultValue": true
        },
        {
          "name": "center",
          "propType": "bool",
          "title": "居中显示",
          "defaultValue": true
        },
        {
          "name": "square",
          "propType": "bool",
          "title": "显示正方形",
          "defaultValue": false
        },
        {
          "name": "clickable",
          "propType": "bool",
          "title": "开启点击反馈",
          "defaultValue": false
        }
      ],
      "configure": {
        "supports": {
          "events": ["click"],
          "loop": true,
          "condition": true,
          "style": true
        },
        "component": {
          "isContainer": true
        }
      }
    },
    {
      "category": "基础组件",
      "componentName": "van-grid-item",
      "npm": {
        "package": "vant",
        "version": "2.12.53",
        "exportName": "GridItem",
        "destructuring": true
      },
      "props": [
        {
          "name": "default",
          "title": "默认插槽",
          "propType": "node"
        },
        {
          "name": "text",
          "description": "文本内容",
          "propType": {
            "type": "oneOfType",
            "value": ["string", "node"]
          },
          "defaultValue": ""
        },
        {
          "name": "icon",
          "propType": {
            "type": "oneOfType",
            "value": ["string", "node"]
          },
          "defaultValue": ""
        },
        {
          "name": "dot",
          "propType": "bool",
          "defaultValue": false
        },
        {
          "name": "badge",
          "propType": "string",
          "defaultValue": ""
        },
        {
          "name": "url",
          "propType": "string",
          "defaultValue": ""
        },
        {
          "name": "to",
          "propType": "string",
          "defaultValue": ""
        },
        {
          "name": "replace",
          "propType": "bool",
          "defaultValue": false
        }
      ],
      "configure": {
        "supports": {
          "events": ["onClick"],
          "loop": true,
          "condition": true,
          "style": true
        },
        "component": {
          "isContainer": false
        }
      }
    }
  ],
  "componentList": [
    {
      "title": "布局组件",
      "children": [
        {
          "componentName": "van-grid",
          "library": "vant",
          "snippets": [
            {
              "screenshot": "https://helios-allpublic-1257616148.cos.ap-shanghai.myqcloud.com/img/card.png",
              "title": "宫格-容器",
              "schema": {
                "componentName": "van-grid",
                "children": []
              }
            }
          ]
        }
      ]
    },
    {
      "title": "布局组件",
      "children": [
        {
          "componentName": "van-grid-item",
          "library": "vant",
          "snippets": [
            {
              "screenshot": "https://helios-allpublic-1257616148.cos.ap-shanghai.myqcloud.com/img/card.png",
              "title": "宫格-子项",
              "schema": {
                "componentName": "van-grid-item",
                "children": []
              }
            }
          ]
        }
      ]
    }
  ]
}
Copyright (c) 2023-PRESENT | wudi