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 🙏

© 2026 – Pkg Stats / Ryan Hefner

real-vue3-easy-form

v1.0.4

Published

基于 Vue 3 + Element Plus 的动态表单组件库,支持配置化生成表单

Readme

Real Vue3 Easy Form 使用手册

基于 Vue 3 + Element Plus 的动态表单组件库,支持配置化生成表单。

目录


安装

环境要求

  • Vue 3.2.0+
  • Element Plus 2.2.0+

安装命令

# 使用 npm
npm install real-vue3-easy-form

# 使用 yarn
yarn add real-vue3-easy-form

# 使用 pnpm
pnpm add real-vue3-easy-form

完整引入

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import EasyForm from 'real-vue3-easy-form'
import 'real-vue3-easy-form/dist/style.css'

const app = createApp(App)

app.use(ElementPlus)
app.use(EasyForm)

app.mount('#app')

快速开始

基本用法

<template>
  <DynamicForm
    :fields="formFields"
    :model-value="formData"
    @update:model-value="handleUpdate"
    @submit="handleSubmit"
  />
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import { DynamicForm } from 'real-vue3-easy-form'
import type { FieldConfig } from 'real-vue3-easy-form'

const formFields: FieldConfig[] = [
  {
    type: 'text',
    label: '用户名',
    prop: 'username',
    placeholder: '请输入用户名',
    required: true,
  },
  {
    type: 'password',
    label: '密码',
    prop: 'password',
    placeholder: '请输入密码',
    required: true,
  },
]

const formData = reactive({
  username: '',
  password: '',
})

const handleUpdate = (val: Record<string, any>) => {
  Object.assign(formData, val)
}

const handleSubmit = (values: Record<string, any>) => {
  console.log('表单数据:', values)
}
</script>

基础配置

字段通用属性

| 属性 | 说明 | 类型 | 默认值 | |------|------|------|--------| | type | 字段类型(必填) | string | - | | label | 字段标签 | string | - | | prop | 字段属性名(必填) | string | - | | placeholder | 占位文本 | string | - | | disabled | 是否禁用 | boolean | false | | readonly | 是否只读 | boolean | false | | required | 是否必填 | boolean | false | | clearable | 是否可清空 | boolean | false | | col | 栅格列宽(1-24) | number | 24 | | offset | 栅格偏移 | number | 0 | | className | 自定义类名 | string | - | | show | 是否显示 | boolean | true | | rules | 验证规则 | array | - | | defaultValue | 默认值 | any | - |


字段类型详解

输入类

1. 文本输入 (text)

{
  type: 'text',
  label: '文本输入',
  prop: 'text',
  placeholder: '请输入文本',
  required: true,
  clearable: true,
  col: 12,
}

2. 文本域 (textarea)

{
  type: 'textarea',
  label: '文本域',
  prop: 'textarea',
  placeholder: '请输入多行文本',
  clearable: true,
  col: 12,
}

3. 数字输入 (number)

{
  type: 'number',
  label: '数字输入',
  prop: 'number',
  placeholder: '请输入数字',
  min: 0,        // 最小值
  max: 100,      // 最大值
  precision: 2,  // 小数位数
  step: 0.1,     // 步长
  col: 12,
}

4. 密码输入 (password)

{
  type: 'password',
  label: '密码输入',
  prop: 'password',
  placeholder: '请输入密码',
  clearable: true,
  col: 12,
}

选择类

1. 下拉选择 (select)

{
  type: 'select',
  label: '下拉选择',
  prop: 'select',
  placeholder: '请选择',
  options: [
    { label: '选项一', value: 1 },
    { label: '选项二', value: 2 },
    { label: '选项三', value: 3 },
  ],
  clearable: true,
  col: 12,
}

2. 单选按钮 (radio)

{
  type: 'radio',
  label: '单选按钮',
  prop: 'radio',
  options: [
    { label: '启用', value: 1 },
    { label: '禁用', value: 0 },
  ],
  col: 12,
}

3. 复选框组 (checkbox)

{
  type: 'checkbox',
  label: '复选框',
  prop: 'checkbox',
  options: [
    { label: '阅读', value: 'reading' },
    { label: '运动', value: 'sports' },
    { label: '音乐', value: 'music' },
    { label: '旅行', value: 'travel' },
  ],
  col: 24,
}

4. 开关 (switch)

{
  type: 'switch',
  label: '开关',
  prop: 'switch',
  activeText: '开',           // 开启状态文本
  inactiveText: '关',         // 关闭状态文本
  activeColor: '#67C23A',     // 开启状态颜色
  inactiveColor: '#909399',   // 关闭状态颜色
  col: 12,
}

5. 滑块 (slider)

// 普通滑块
{
  type: 'slider',
  label: '滑块',
  prop: 'slider',
  min: 0,
  max: 100,
  step: 5,
  col: 12,
}

// 范围滑块
{
  type: 'slider',
  label: '范围滑块',
  prop: 'sliderRange',
  min: 0,
  max: 100,
  step: 1,
  range: true,  // 开启范围选择
  marks: { 0: '0%', 50: '50%', 100: '100%' },  // 刻度标记
  col: 24,
}

日期时间类

1. 日期选择 (date)

{
  type: 'date',
  label: '日期选择',
  prop: 'date',
  placeholder: '请选择日期',
  format: 'YYYY-MM-DD',      // 显示格式
  valueFormat: 'YYYY-MM-DD', // 值格式
  clearable: true,
  col: 8,
}

2. 时间选择 (time)

{
  type: 'time',
  label: '时间选择',
  prop: 'time',
  placeholder: '请选择时间',
  format: 'HH:mm:ss',
  valueFormat: 'HH:mm:ss',
  clearable: true,
  col: 8,
}

3. 日期时间选择 (datetime)

{
  type: 'datetime',
  label: '日期时间',
  prop: 'datetime',
  placeholder: '请选择日期时间',
  format: 'YYYY-MM-DD HH:mm:ss',
  valueFormat: 'YYYY-MM-DD HH:mm:ss',
  clearable: true,
  col: 8,
}

树形选择

1. 普通树形选择 (tree_select)

{
  type: 'tree_select',
  label: '树形选择',
  prop: 'treeSelect',
  placeholder: '请选择',
  clearable: true,
  filterable: true,        // 支持搜索
  defaultExpandAll: true,  // 默认展开全部
  nodeKey: 'id',           // 节点唯一标识字段
  treeData: [
    {
      id: 1,
      label: '技术部',
      children: [
        { id: 11, label: '前端组', children: [{ id: 111, label: 'Vue小组' }, { id: 112, label: 'React小组' }] },
        { id: 12, label: '后端组', children: [{ id: 121, label: 'Java小组' }, { id: 122, label: 'Python小组' }] },
        { id: 13, label: '移动端组' },
      ]
    },
    {
      id: 2,
      label: '运营部',
      children: [{ id: 21, label: '市场组' }, { id: 22, label: '策划组' }]
    },
    { id: 3, label: '人事部' },
    { id: 4, label: '财务部' },
  ],
  col: 12,
}

2. 多选树形选择 (tree_select)

{
  type: 'tree_select',
  label: '多选树形',
  prop: 'treeSelectMultiple',
  placeholder: '请选择',
  clearable: true,
  filterable: true,
  checkStrictly: true,     // 是否严格的遵守父子不互相关联
  showCheckbox: true,      // 显示复选框
  defaultExpandAll: true,
  nodeKey: 'id',
  treeMultiple: true,      // 开启多选
  treeData: [
    { id: 1, label: '技术部', children: [{ id: 11, label: '前端' }, { id: 12, label: '后端' }] },
    { id: 2, label: '运营部' },
    { id: 3, label: '人事部' },
  ],
  col: 12,
}

高级组件

1. 评分 (rate)

{
  type: 'rate',
  label: '评分',
  prop: 'rate',
  max: 5,              // 最大分值
  allowHalf: false,    // 是否允许半选
  showText: true,      // 显示辅助文字
  texts: ['极差', '失望', '一般', '满意', '惊喜'],
  col: 12,
}

2. 颜色选择器 (color_picker)

{
  type: 'color_picker',
  label: '颜色选择',
  prop: 'colorPicker',
  showAlpha: false,    // 是否支持透明度选择
  colorFormat: 'hex',   // 颜色的格式 (hex/rgb/hsl)
  col: 12,
}

3. 图标选择器 (icon_select)

{
  type: 'icon_select',
  label: '图标选择',
  prop: 'iconSelect',
  placeholder: '请选择图标',
  iconSearchable: true,  // 图标可搜索
  iconShowTabs: true,    // 显示分类标签
  showInputIcon: true,   // 在输入框中显示图标
  col: 24,
}

4. 富文本编辑器 (editor)

{
  type: 'editor',
  label: '富文本编辑器',
  prop: 'editor',
  placeholder: '请输入内容...',
  height: 300,  // 编辑器高度
  toolbarConfig: {
    excludeKeys: ['group-video']  // 排除的工具栏功能
  },
  col: 24,
}

上传类

1. 图片上传 (image)

{
  type: 'image',
  label: '图片上传',
  prop: 'image',
  accept: 'image/*',           // 接受的文件类型
  maxCount: 3,                 // 最大上传数量
  action: '/api/upload',       // 上传地址
  multiple: true,              // 是否多选
  autoUpload: false,           // 是否自动上传
  col: 12,
}

2. 文件上传 (file)

{
  type: 'file',
  label: '文件上传',
  prop: 'file',
  accept: '.pdf,.doc,.docx,.xls,.xlsx',  // 接受的文件类型
  maxSize: 10,                // 单个文件大小限制(MB)
  maxCount: 5,                // 最大上传数量
  action: '/api/upload',
  multiple: true,
  autoUpload: false,
  col: 12,
}

字段列表

字段列表是一种特殊类型,可以动态添加/删除多个子项,适合需要输入多条记录的场景。

1. 二维模式 - 成员列表 (fieldlist)

{
  type: 'fieldlist',
  label: '成员列表',
  prop: 'members',
  listAddText: '添加成员',      // 添加按钮文本
  listDeleteText: '删除',      // 删除按钮文本
  listMaxCount: 10,           // 最大条数
  listSortable: true,        // 是否可拖拽排序
  listColumns: [              // 子项的列配置
    { 
      type: 'text', 
      prop: 'name', 
      label: '姓名', 
      placeholder: '请输入姓名' 
    },
    { 
      type: 'select', 
      prop: 'role', 
      label: '角色', 
      options: [
        { label: '管理员', value: 'admin' },
        { label: '成员', value: 'member' }
      ]
    },
    { 
      type: 'text', 
      prop: 'email', 
      label: '邮箱', 
      placeholder: '请输入邮箱' 
    },
  ],
  col: 24,
}

初始化数据格式:

members: [
  { name: '张三', role: 'admin', email: '[email protected]' },
  { name: '李四', role: 'member', email: '[email protected]' }
]

2. 一维模式 - 商品清单 (fieldlist)

{
  type: 'fieldlist',
  label: '商品清单',
  prop: 'products',
  listMode: '1d',              // 使用一维模式
  listItemLabel: 'name',       // 显示字段名
  listAddText: '添加商品',
  listMaxCount: 10,
  col: 24,
}

初始化数据格式:

products: ['商品A', '商品B']

组件属性

DynamicForm 属性

| 属性 | 说明 | 类型 | 默认值 | |------|------|------|--------| | fields | 字段配置数组(必填) | FieldConfig[] | - | | modelValue | 表单数据对象(必填) | Record<string, any> | {} | | rules | 表单验证规则 | Record<string, any[]> | {} | | labelWidth | 标签宽度 | string \| number | '120px' | | labelPosition | 标签位置 | 'left' \| 'right' \| 'top' | 'right' | | size | 表单尺寸 | 'large' \| 'default' \| 'small' | 'default' | | inline | 是否行内表单 | boolean | false | | disabled | 是否禁用整个表单 | boolean | false | | gutter | 栅格间距 | number | 16 | | showActions | 是否显示操作按钮 | boolean | true | | submitText | 提交按钮文本 | string | '提交' | | submitLoading | 提交按钮加载状态 | boolean | false | | enableDraft | 启用草稿功能 | boolean | false | | draftKey | 草稿存储键名 | string | 'form_draft' | | draftTTL | 草稿有效期(毫秒) | number | 7 * 24 * 60 * 60 * 1000 | | showDraftTip | 显示草稿提示 | boolean | true |


组件事件

DynamicForm 事件

| 事件名 | 说明 | 参数 | |--------|------|------| | update:modelValue | 表单数据变化时触发 | (value: Record<string, any>) | | submit | 提交表单时触发 | (value: Record<string, any>) | | reset | 重置表单时触发 | () | | change | 字段值变化时触发 | (field: FieldConfig, value: any) | | input | 字段输入时触发 | (field: FieldConfig, value: any) | | validate | 表单验证结果 | (valid: boolean) |


高级功能

1. 草稿保存

开启草稿功能后,表单数据会自动保存到 localStorage,防止意外丢失。

<DynamicForm
  :fields="formFields"
  :model-value="formData"
  :enable-draft="true"
  :draft-key="'my-form-draft'"
  :draft-ttl="7 * 24 * 60 * 60 * 1000"
  :show-draft-tip="true"
  @update:model-value="handleUpdate"
  @submit="handleSubmit"
/>

2. 自定义操作按钮

<template>
  <DynamicForm
    :fields="formFields"
    v-model="formData"
    @submit="handleSubmit"
  >
    <template #actions>
      <el-button type="primary" @click="customSubmit">保存</el-button>
      <el-button type="success" @click="customSaveDraft">保存草稿</el-button>
      <el-button @click="customReset">重置</el-button>
    </template>
  </DynamicForm>
</template>

3. 获取表单实例方法

通过 ref 获取表单实例,可以调用验证、重置等方法。

<template>
  <DynamicForm
    ref="formRef"
    :fields="formFields"
    v-model="formData"
  />
  <el-button @click="validateForm">验证表单</el-button>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import type { FormInstance } from 'element-plus'

const formRef = ref()

const validateForm = async () => {
  const valid = await formRef.value?.validate()
  if (valid) {
    console.log('表单验证通过')
  }
}

// 暴露的方法
// formRef.value?.validate()     - 验证表单
// formRef.value?.reset()        - 重置表单
// formRef.value?.clearValidate() - 清除验证
// formRef.value?.getData()      - 获取表单数据
// formRef.value?.setData(data)   - 设置表单数据
</script>

4. 动态显示字段 (favisible)

根据其他字段的值动态显示或隐藏字段。

{
  type: 'text',
  label: '姓名',
  prop: 'name',
},
{
  type: 'text',
  label: '详细地址',
  prop: 'address',
  favisible: 'name=张三',  // 当 name 等于"张三"时显示
}

示例代码

完整示例 - 用户信息表单

<template>
  <div class="form-demo">
    <h1>用户信息表单</h1>
    
    <DynamicForm
      ref="formRef"
      :fields="formFields"
      :model-value="formData"
      @update:model-value="(val) => Object.assign(formData, val)"
      @submit="handleSubmit"
      @reset="handleReset"
    />
    
    <div class="debug-info">
      <h3>表单数据预览:</h3>
      <pre>{{ JSON.stringify(formData, null, 2) }}</pre>
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue'
import { DynamicForm } from 'real-vue3-easy-form'
import type { FieldConfig } from 'real-vue3-easy-form'
import { ElMessage } from 'element-plus'

const formFields: FieldConfig[] = [
  {
    type: 'text',
    label: '姓名',
    prop: 'name',
    placeholder: '请输入姓名',
    required: true,
    col: 12,
  },
  {
    type: 'select',
    label: '性别',
    prop: 'gender',
    options: [
      { label: '男', value: 'male' },
      { label: '女', value: 'female' },
    ],
    col: 12,
  },
  {
    type: 'number',
    label: '年龄',
    prop: 'age',
    min: 1,
    max: 150,
    col: 12,
  },
  {
    type: 'date',
    label: '出生日期',
    prop: 'birthday',
    format: 'YYYY-MM-DD',
    valueFormat: 'YYYY-MM-DD',
    col: 12,
  },
  {
    type: 'text',
    label: '手机号',
    prop: 'phone',
    placeholder: '请输入手机号',
    required: true,
    col: 12,
  },
  {
    type: 'text',
    label: '邮箱',
    prop: 'email',
    placeholder: '请输入邮箱',
    rules: [
      { type: 'email', message: '请输入正确的邮箱格式' }
    ],
    col: 12,
  },
  {
    type: 'textarea',
    label: '个人简介',
    prop: 'bio',
    placeholder: '请输入个人简介',
    col: 24,
  },
]

const formData = reactive({
  name: '',
  gender: '',
  age: null,
  birthday: '',
  phone: '',
  email: '',
  bio: '',
})

const handleSubmit = (values: Record<string, any>) => {
  console.log('提交数据:', values)
  ElMessage.success('提交成功!')
}

const handleReset = () => {
  ElMessage.info('表单已重置')
}
</script>

<style scoped>
.form-demo {
  max-width: 800px;
  margin: 40px auto;
  padding: 20px;
}

.debug-info {
  margin-top: 30px;
  padding: 15px;
  background: #f5f7fa;
  border-radius: 8px;
}

.debug-info pre {
  background: #fff;
  padding: 15px;
  border-radius: 4px;
  overflow-x: auto;
}
</style>

更新日志

v1.0.3 (当前版本)

  • 支持多种字段类型(输入、选择、日期、树形、上传等)
  • 内置富文本编辑器(wangEditor)
  • 支持字段列表(动态添加/删除多条记录)
  • 支持草稿自动保存
  • 支持动态显示/隐藏字段

常见问题

1. 为什么表单无法输入或选择?

确保使用了正确的绑定方式:

<!-- 正确 -->
<DynamicForm
  :model-value="formData"
  @update:model-value="(val) => Object.assign(formData, val)"
/>

<!-- 错误 -->
<DynamicForm v-model="formData" />

2. 如何自定义验证规则?

{
  type: 'text',
  label: '邮箱',
  prop: 'email',
  rules: [
    { required: true, message: '请输入邮箱', trigger: 'blur' },
    { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
  ]
}

3. 如何获取表单实例的方法?

const formRef = ref()

// 验证表单
const valid = await formRef.value?.validate()

// 获取数据
const data = formRef.value?.getData()

// 设置数据
formRef.value?.setData({ name: '张三' })

// 重置表单
formRef.value?.reset()

License

MIT License - 2024