npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

config-form-generator

v1.2.0

Published

A configuration-based form generator for Vue 3 + Element Plus

Readme

ConfigForm Generator

ConfigForm Generator 是一个逻辑与 UI 分离的配置化表单生成方案。目前的默认实现基于 Vue 3 + Element Plus,但其核心引擎(状态管理、校验、联动逻辑)是完全独立的,可以轻松适配 Ant Design VueNaive UI 或其他 UI 库。

💡 核心理念:通过 JSON Schema 描述表单结构、验证规则和联动逻辑,实现“一次配置,多端渲染”或“后端驱动前端表单”。

✨ 特性 (Features)

  • 🛡️ UI 无关核心 (UI Agnostic Core): 核心逻辑层不依赖任何特定 UI 库,仅通过适配器层渲染。
  • 📝 配置驱动: 完全通过 JSON Schema 描述表单,支持无限嵌套布局。
  • 🦾 类型安全: 完整的 TypeScript 类型定义,开发体验友好。
  • 🔗 智能联动: 内置强大的表达式引擎 ({{ model.xxx }}),支持字段间的复杂依赖(显示/隐藏、禁用/启用、值联动等)。
  • 🔌 扩展性强: 所有的组件(输入框、布局容器)均通过注册表管理,可自由替换或扩展自定义组件。
  • ⚡️ 高性能: 细粒度的依赖追踪,只有相关字段才会触发更新。

🧩 架构说明 (Architecture)

项目采用 Core + Adapter 的架构设计:

  1. Core Layer (src/core):

    • Registry: 组件注册中心,管理字符串 ('input') 到具体 Vue 组件的映射。
    • State Management: 维护表单数据模型 (Model) 和 UI 状态 (Shadow State)。
    • Linkage Engine: 处理字段间的依赖关系和动态计算。
    • 此层完全不包含 Element Plus 代码。
  2. Adapter Layer (src/components/ConfigForm):

    • 目前的实现是 Element Plus Adapter
    • ConfigForm.vue: 封装了 <el-form>
    • ConfigFormItem.vue: 封装了 <el-form-item> 并处理通用属性映射。
    • 如果你想使用 Ant Design,只需重写这一层即可。

🚀 快速开始 (Quick Start)

1. 安装依赖

本项目需要 Vue 3 和 Element Plus(作为默认 UI 库)。

# 安装核心库
npm install config-form-generator

# 安装 UI 库 (如果尚未安装)
npm install element-plus

2. 引入组件与样式

在你的入口文件(如 main.ts)或组件中引入。

import { createApp } from 'vue';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import App from './App.vue';

// 引入 ConfigForm Generator 样式
import 'config-form-generator/dist/style.css';

const app = createApp(App);
app.use(ElementPlus);
app.mount('#app');

3. 组件注册

ConfigForm 组件在挂载时会默认注册 Element Plus 的常用组件预设(通过 useElementPlusPresets)。

如果你需要注册自定义组件或覆盖默认组件,可以使用 registerComponent

import { registerComponent } from 'config-form-generator';
import MyCustomInput from './MyCustomInput.vue';

// 注册自定义组件
registerComponent('my-input', MyCustomInput);

4. 基础使用示例

<script setup lang="ts">
import { ref } from 'vue';
import { ConfigForm } from 'config-form-generator';
import type { FormConfig } from 'config-form-generator/dist/core/types';

const formData = ref({});

const formConfig: FormConfig = {
  labelWidth: '100px',
  schemas: [
    {
      category: 'field',
      type: 'input',
      field: 'username',
      label: '用户名',
      props: { placeholder: '请输入用户名' },
      rules: [{ required: true, message: '必填项', trigger: 'blur' }]
    },
    {
      category: 'field',
      type: 'select',
      field: 'role',
      label: '角色',
      props: {
        options: [
          { label: '管理员', value: 'admin' },
          { label: '用户', value: 'user' }
        ]
      }
    }
  ]
};

const handleSubmit = (data: any) => {
  console.log('表单提交:', data);
};
</script>

<template>
  <ConfigForm 
    :config="formConfig" 
    v-model="formData" 
    @submit="handleSubmit" 
  />
</template>

📖 配置手册 (Configuration Guide)

1. FormConfig (表单根配置)

| 属性 | 类型 | 默认值 | 说明 | | :--- | :--- | :--- | :--- | | schemas | FormSchema[] | [] | 核心。表单项的配置数组。 | | labelWidth | string | number | '100px' | 全局标签宽度。 | | labelPosition | 'left' | 'right' | 'top' | 'right' | 标签对齐方式。 | | size | 'large' | 'default' | 'small' | 'default' | 表单组件尺寸。 | | disabled | boolean | false | 全局禁用表单。 | | hideRequiredAsterisk | boolean | false | 隐藏必填字段的星号。 | | context | Record<string, any> | {} | 外部上下文数据,可用于联动表达式 {{ context.xxx }}。 | | hiddenFields | string[] | [] | 强制隐藏的组件列表(黑名单)。⚠️ 注意:仅支持通过 Key 匹配(必须确保 Schema 中定义了 key),不支持 field。 | | editableFields | string[] | [] | 查看模式 (mode='view') 下的编辑白名单。⚠️ 注意:仅支持通过 Key 匹配,不支持 field。 |

2. FormSchema (表单项配置)

表单项主要分为两类:字段 (Field)容器 (Container)

A. FieldSchema (字段配置)

用于产生值的输入控件。

| 属性 | 类型 | 说明 | | :--- | :--- | :--- | | category | 'field' | 必填。标识为字段。 | | type | string | 必填。组件类型(需先通过 registerComponent 注册),如 'input', 'select'。 | | field | string | 必填。绑定的数据字段路径,支持嵌套如 'user.name'。 | | label | string | 标签文本。 | | defaultValue | any | 默认值。 | | props | Record<string, any> | 透传给组件的 props,如 placeholder, clearable 等。支持表达式。 | | rules | RuleItem[] | 校验规则(同 Element Plus / Async-Validator)。 | | visible | boolean | string | 是否显示。支持表达式 {{ model.age > 18 }}。 | | disabled | boolean | string | 是否禁用。支持表达式。 | | required | boolean | string | 是否必填。支持表达式。 | | col | ColLayout | 栅格布局配置,如 { span: 12 }。 | | dependencies | DependencyConfig[] | 高级联动配置。 |

B. ContainerSchema (容器配置)

用于布局,不产生数据值。

| 属性 | 类型 | 说明 | | :--- | :--- | :--- | | category | 'container' | 必填。标识为容器。 | | type | string | 必填。容器组件类型,如 'card', 'grid', 'tabs'。 | | children | FormSchema[] | 子节点 Schema 数组。 | | props | Record<string, any> | 透传给容器组件的 props。 | | visible | boolean | string | 是否显示容器。 | | scope | string | 数据作用域。若设置,子字段将基于此路径绑定。例如 scope 为 'user',子字段 'name' 实际绑定 'user.name'。 |


🔗 智能联动系统 (Smart Linkage)

这是本库最核心的功能,支持两种方式定义联动:

1. 表达式联动 (Expression)

最简单直观的方式,直接在属性中使用 {{ }} 语法。

  • 支持的属性: visible, disabled, required, label, props 内的任意属性。
  • 可用变量:
    • model: 当前表单的完整数据对象。
    • context: 外部传入的上下文。

示例

{
  "type": "input",
  "field": "reason",
  "label": "拒绝原因",
  "visible": "{{ model.status === 'reject' }}",
  "props": {
    "placeholder": "{{ model.type === 'personal' ? '请输入个人原因' : '请输入公事原因' }}"
  }
}

2. 依赖配置 (Dependencies)

当表达式无法满足需求(如需要修改值、修改选项、触发异步请求)时,使用 dependencies

interface DependencyConfig {
  source: string | string[]; // 监听的字段,如 'role'
  trigger?: 'change' | 'blur' | 'init'; // 触发时机
  type: 'value' | 'options' | 'visible' | 'disabled' | ...; // 联动类型
  target?: string; // 目标字段(默认为当前字段)
  expression?: string; // 逻辑表达式
}

示例:角色决定权限选项

{
  "type": "select",
  "field": "permissions",
  "dependencies": [
    {
      "source": "role",
      "type": "options",
      "expression": "model.role === 'admin' ? [{label:'全部',value:'all'}] : [{label:'部分',value:'part'}]"
    }
  ]
}

🧩 自定义组件开发

你可以轻松编写自定义组件并集成到表单中。

1. 编写组件 (MyCustomInput.vue)

组件只需满足:

  1. 接收 modelValue prop。
  2. 触发 update:modelValue event。
<script setup lang="ts">
defineProps(['modelValue', 'placeholder']);
defineEmits(['update:modelValue']);
</script>

<template>
  <div class="my-custom-input">
    <input 
      :value="modelValue" 
      @input="$emit('update:modelValue', ($event.target as any).value)"
      :placeholder="placeholder"
    />
  </div>
</template>

2. 注册组件

import { registerComponent } from 'config-form-generator';
import MyCustomInput from './MyCustomInput.vue';

registerComponent('my-input', MyCustomInput);

3. 在 Schema 中使用

{
  "category": "field",
  "type": "my-input",
  "field": "customField",
  "label": "自定义组件",
  "props": {
    "placeholder": "这是透传的属性"
  }
}

❓ 常见问题

Q: 为什么默认不内置 Input 等组件? A: 为了保持核心包体积最小,且不强制依赖特定版本的 UI 库。你可以按需注册,甚至混用 Element Plus 和 Ant Design 的组件。

Q: 支持 TypeScript 吗? A: 完全支持。请使用 FormConfig, FormSchema 等类型定义来获得完整的代码提示。

Q: 如何进行表单校验? A: 通过 ref 获取组件实例,调用 validate 方法:

const formRef = ref();
// ...
await formRef.value.validate();

License

MIT