Skip to content

useSchema 表单架构钩子函数文档

一、功能概述

useSchema 是基于 Formily 和 Vue 3 的表单架构管理钩子,用于实现表单组件的注册、绑定与动态管理。它通过桥接 Formily 的 Schema 系统与 UI 组件库(如 Element Plus),提供了灵活的组件注册机制,支持公共组件与自定义组件的分层管理,适用于复杂表单场景的组件扩展与定制。

二、核心特性

  1. 组件分层管理

    • 公共组件库publicComponentStore):内置 Element Plus 常用表单组件(如 InputRadioCheckbox 等),支持全局覆盖。
    • 自定义组件库customComponentStore):用于注册应用内自定义组件,优先级高于公共组件。
  2. 动态组件注册
    通过 setFormilyComponent 方法动态注册组件,支持指定组件类型(公共/自定义),实现组件的按需加载与替换。

  3. 响应式 Schema 生成
    使用 computed 生成响应式的 FormilySchema,确保组件变更时自动更新表单架构。

三、核心概念与接口

1. 组件类型枚举(FormilyComponentType

typescript
export enum FormilyComponentType {
  PUBLIC, // 公共组件(全局作用域,可被自定义组件覆盖)
  CUSTOM // 自定义组件(应用作用域,优先级高于公共组件)
}

2. 组件存储接口(SchemaVueComponents

typescript
interface SchemaVueComponents {
  [key: string]: VueComponent // 组件名到 Vue 组件的映射
}

3. 返回值说明

名称类型说明
FormilySchemaComputedRef<SchemaField>响应式 Formily Schema 实例,用于在模板中渲染表单组件
setFormilyComponent(name: string, component: VueComponent, type?: FormilyComponentType) => void注册组件的方法

四、使用流程

1. 基础使用:渲染内置组件

vue
<template>
  <FormilySchema
    :schema="{
      type: 'object',
      properties: {
        username: {
          type: 'string',
          title: '用户名',
          'x-component': 'Input' // 使用内置 Input 组件
        }
      }
    }"
  />
</template>

<script setup>
import { useSchema } from './useSchema'

const { FormilySchema } = useSchema()
</script>

2. 注册自定义组件(覆盖内置组件)

vue
<template>
  <FormilySchema
    :schema="{
      type: 'object',
      properties: {
        password: {
          type: 'string',
          title: '密码',
          'x-component': 'CustomPasswordInput' // 使用自定义组件
        }
      }
    }"
  />
</template>

<script setup>
import { useSchema } from './useSchema'
import CustomPasswordInput from './CustomPasswordInput.vue' // 自定义密码输入组件

const { setFormilyComponent } = useSchema()

// 注册自定义组件到自定义作用域(CUSTOM 类型可省略)
setFormilyComponent('CustomPasswordInput', CustomPasswordInput)
</script>

3. 全局覆盖公共组件(如修改 Input 样式)

typescript
// 在全局初始化文件中
import { useSchema } from './useSchema'
import { Input } from '@formily/element-plus'
import CustomInput from './CustomInput.vue'

const { setFormilyComponent } = useSchema()

// 覆盖公共组件库中的 Input 组件
setFormilyComponent('Input', CustomInput, FormilyComponentType.PUBLIC)

五、API 详解

setFormilyComponent 方法

参数说明

参数名类型必填默认值说明
namestring-组件名称(需与 Schema 中 x-component 一致)
componentVueComponent-Vue 组件(可以是 defineComponent 或组件引用)
typeFormilyComponentTypeFormilyComponentType.CUSTOM组件类型(公共/自定义)

示例:注册公共组件

typescript
// 注册一个公共组件(所有表单实例均可访问)
setFormilyComponent('MyButton', MyButtonComponent, FormilyComponentType.PUBLIC)

六、注意事项

  1. 组件命名冲突

    • 自定义组件(CUSTOM)会覆盖同名的公共组件(PUBLIC)。
    • 公共组件会覆盖 Formily 内置的默认组件(如 Input)。
  2. 组件通信要求
    自定义组件需遵循 Formily 的 组件协议,至少包含 valueonChange 等属性。

  3. 性能优化

    • 避免在高频更新场景中动态注册组件,建议在组件初始化阶段完成注册。
    • 大型项目可通过 defineAsyncComponent 实现组件的异步加载。

七、扩展场景

场景 1:动态切换组件库(Element Plus ↔ Ant Design)

typescript
// 定义组件库映射
const componentLibs = {
  element: {
    Input: () => import('@formily/element-plus').Input,
    Button: () => import('@formily/element-plus').Button
  },
  antd: {
    Input: () => import('@formily/antd').Input,
    Button: () => import('@formily/antd').Button
  }
}

// 动态切换组件库
function switchComponentLib(libName: 'element' | 'antd') {
  const lib = componentLibs[libName]
  Object.keys(lib).forEach(name => {
    setFormilyComponent(name, lib[name], FormilyComponentType.PUBLIC)
  })
}

场景 2:基于 Props 动态渲染组件

vue
<template>
  <FormilySchema
    :schema="{
      type: 'object',
      properties: {
        field: {
          type: 'string',
          title: '动态组件',
          'x-component': dynamicComponentName, // 动态组件名
          'x-component-props': { size: 'large' } // 组件 Props
        }
      }
    }"
  />
</template>

<script setup>
import { ref } from 'vue'
import { useSchema } from './useSchema'

const dynamicComponentName = ref('Input') // 可通过逻辑动态修改为 'Select'、'Textarea' 等
const { FormilySchema } = useSchema()
</script>

八、依赖说明

  • 核心依赖
    • @formily/vue:Formily 的 Vue 适配层
    • @formily/element-plus:Element Plus 组件库适配(示例中使用,可替换为其他库)
  • Vue 版本:需使用 Vue 3.x(Composition API 支持)
  • 类型声明:依赖 @formily/vue/type-artefacts 提供的类型定义

仅供内部学习使用