更新记录

v1.0.0(2025-10-13)

更新日志

[1.0.0] - 2025-10-13

✨ 新增

核心功能

  • ✅ 基于 Vue2 的动态表单生成器
  • ✅ 支持 uni-app 多端(H5、小程序、App)
  • ✅ 完整的表单验证系统
  • ✅ Maker API 链式调用支持

表单组件(14个)

  • ✅ input - 文本输入框
  • ✅ textarea - 多行文本
  • ✅ number - 数字输入
  • ✅ password - 密码输入
  • ✅ select - 下拉选择
  • ✅ radio - 单选框
  • ✅ checkbox - 复选框
  • ✅ switch - 开关
  • ✅ slider - 滑块
  • ✅ rate - 评分
  • ✅ picker - uni-app 原生选择器
  • ✅ datePicker - 日期选择
  • ✅ timePicker - 时间选择
  • ✅ upload - 文件上传

验证功能

  • ✅ 内置验证规则(必填、邮箱、手机号等)
  • ✅ 自定义验证器
  • ✅ 同步/异步验证
  • ✅ 字段级验证
  • ✅ 表单级验证

API 功能

  • ✅ formData() - 获取表单数据
  • ✅ setValue() - 设置表单值
  • ✅ getValue() - 获取字段值
  • ✅ validate() - 验证表单
  • ✅ validateField() - 验证单个字段
  • ✅ resetFields() - 重置表单
  • ✅ clearValidate() - 清空验证
  • ✅ submit() - 提交表单
  • ✅ updateRule() - 更新规则
  • ✅ hidden() - 隐藏字段
  • ✅ display() - 显示字段
  • ✅ disabled() - 禁用字段
  • ✅ refresh() - 刷新表单

工具函数

  • ✅ maker - 规则构造器
  • ✅ util - 通用工具函数
  • ✅ validate - 验证工具
  • ✅ createValidator - 创建验证器
  • ✅ addValidator - 添加自定义验证器

文档

  • ✅ 完整的 README 文档
  • ✅ 快速开始指南
  • ✅ 示例页面
  • ✅ API 文档


平台兼容性

form-create-plugin

基于 uni-app Vue2 的动态表单生成插件,支持快速创建和验证表单。

📌 版本要求

✅ 支持的版本

  • HBuilderX: ≥ 3.0.0(推荐 3.6.0+)
  • uni-app: ≥ 3.0.0
  • Vue: 2.6.14+
  • 编译器版本: 3

✅ 支持的平台

  • ✓ H5
  • ✓ 微信小程序
  • ✓ 支付宝小程序
  • ✓ 百度小程序
  • ✓ 字节小程序
  • ✓ QQ小程序
  • ✓ App(Vue)
  • × App(nvue)- 暂不支持
  • × uni-app x - 暂不支持

⚠️ 重要说明

  • 本插件基于 Vue2 开发,不支持 uni-app x
  • uni-app x 是基于 uts 的全新架构,需要单独适配
  • 如需 Vue3 或 uni-app x 支持,请关注后续版本

✨ 特性

  • 🚀 快速开发 - 通过 JSON 配置快速生成表单
  • 🎨 丰富组件 - 内置 14+ 常用表单组件
  • 表单验证 - 支持同步/异步验证,自定义验证规则
  • 🔧 灵活配置 - 支持动态显示/隐藏、禁用等
  • 📱 跨平台 - 支持 H5、小程序、App 等多端
  • 💡 易于扩展 - 支持自定义组件和验证器

📦 安装

方式一:直接引入

form-create-plugin 文件夹复制到项目的 plugins 目录下。

方式二:npm 安装(待发布)

npm install @pfinal/form-create-uniapp

🚀 快速开始

1. 引入插件

main.js 中引入并使用插件:

import Vue from 'vue'
import FormCreate from '@/plugins/form-create-plugin'

Vue.use(FormCreate)

2. 使用表单

方式一:使用 maker 构造器(推荐)

<template>
  <view>
    <form-create 
      :rule="rule" 
      :option="option"
      @mounted="handleMounted"
    />
    <button @click="submit">提交</button>
  </view>
</template>

<script>
export default {
  data() {
    return {
      fapi: null,
      rule: [],
      option: {
        onSubmit: this.handleSubmit
      }
    }
  },
  created() {
    const { maker } = this.$formCreate

    this.rule = [
      maker.input('username', '用户名')
        .value('')
        .placeholder('请输入用户名')
        .required('用户名不能为空')
        .getRule(),

      maker.password('password', '密码')
        .value('')
        .placeholder('请输入密码')
        .required('密码不能为空')
        .addValidate({
          min: 6,
          message: '密码长度不能少于6位'
        })
        .getRule(),

      maker.select('gender', '性别')
        .options([
          { label: '男', value: 'male' },
          { label: '女', value: 'female' }
        ])
        .required('请选择性别')
        .getRule(),

      maker.switch('agree', '同意协议')
        .value(false)
        .required('请同意用户协议')
        .getRule()
    ]
  },
  methods: {
    handleMounted(fapi) {
      this.fapi = fapi
    },

    async submit() {
      try {
        const formData = await this.fapi.submit()
        console.log('表单数据:', formData)
        uni.showToast({ title: '提交成功' })
      } catch (errors) {
        console.log('验证失败:', errors)
        uni.showToast({ 
          title: '请检查表单', 
          icon: 'none' 
        })
      }
    },

    handleSubmit(formData, fapi) {
      console.log('表单提交:', formData)
    }
  }
}
</script>

方式二:直接配置规则

export default {
  data() {
    return {
      rule: [
        {
          type: 'input',
          field: 'username',
          title: '用户名',
          value: '',
          props: {
            placeholder: '请输入用户名'
          },
          validate: [
            { required: true, message: '用户名不能为空' }
          ]
        },
        {
          type: 'password',
          field: 'password',
          title: '密码',
          value: '',
          props: {
            placeholder: '请输入密码'
          },
          validate: [
            { required: true, message: '密码不能为空' },
            { min: 6, message: '密码长度不能少于6位' }
          ]
        }
      ]
    }
  }
}

📚 API 文档

FormCreate 组件属性

属性 说明 类型 默认值
rule 表单生成规则 Array []
option 表单配置项 Object {}
value 表单初始值 Object {}
showMessage 是否显示验证消息 Boolean true

FormCreate 事件

事件名 说明 回调参数
mounted 表单挂载完成 fapi
submit 表单提交 formData, fapi
change 字段值改变 field, value

formCreate API (fapi)

// 获取表单数据
fapi.formData()

// 设置表单值
fapi.setValue('username', '张三')
fapi.setValue({ username: '张三', age: 18 })

// 获取字段值
fapi.getValue('username')

// 验证表单
await fapi.validate()

// 验证单个字段
await fapi.validateField('username')

// 清空验证
fapi.clearValidate()
fapi.clearValidate('username')

// 重置表单
fapi.resetFields()

// 提交表单
await fapi.submit()

// 更新规则
fapi.updateRule('username', { title: '新标题' })

// 显示/隐藏字段
fapi.hidden('username', true)
fapi.display('username', false)

// 禁用/启用字段
fapi.disabled('username', true)

// 刷新表单
fapi.refresh()

🎯 表单组件

输入类

input - 文本输入框

maker.input('field', '标题').value('').placeholder('请输入')

textarea - 多行文本

maker.textarea('field', '标题').props({ autoHeight: true })

number - 数字输入

maker.number('field', '标题').value(0)

password - 密码输入

maker.password('field', '标题').props({ showToggle: true })

选择类

select - 下拉选择

maker.select('field', '标题')
  .options([
    { label: '选项1', value: '1' },
    { label: '选项2', value: '2' }
  ])

radio - 单选框

maker.radio('field', '标题')
  .options(['选项1', '选项2'])

checkbox - 复选框

maker.checkbox('field', '标题')
  .options(['选项1', '选项2'])
  .value([])

switch - 开关

maker.switch('field', '标题').value(false)

日期时间

datePicker - 日期选择

maker.datePicker('field', '标题')
  .props({ start: '2020-01-01', end: '2030-12-31' })

timePicker - 时间选择

maker.timePicker('field', '标题')

picker - uni-app 原生选择器

maker.picker('field', '标题')
  .props({ mode: 'selector' })
  .options(['选项1', '选项2'])

其他

slider - 滑块

maker.slider('field', '标题')
  .value(0)
  .props({ min: 0, max: 100, step: 1 })

rate - 评分

maker.rate('field', '标题')
  .value(0)
  .props({ count: 5 })

upload - 上传

maker.upload('field', '标题')
  .value([])
  .props({
    maxCount: 9,
    action: 'http://api.com/upload'
  })

✅ 表单验证

内置验证规则

// 必填
{ required: true, message: '必填项' }

// 长度验证
{ min: 6, message: '最少6个字符' }
{ max: 20, message: '最多20个字符' }
{ len: 11, message: '必须11个字符' }

// 类型验证
{ type: 'email', message: '邮箱格式不正确' }
{ type: 'mobile', message: '手机号格式不正确' }
{ type: 'number', message: '必须是数字' }

// 正则验证
{ pattern: /^[a-zA-Z]+$/, message: '只能输入字母' }

自定义验证

maker.input('email', '邮箱')
  .addValidate({
    validator: async (value, rule) => {
      // 返回 false 或错误信息表示验证失败
      if (!value) return '邮箱不能为空'
      if (!/^[\w-]+@[\w-]+\.[\w-]+$/.test(value)) {
        return '邮箱格式不正确'
      }
      // 异步验证
      const exists = await checkEmailExists(value)
      if (exists) return '邮箱已被注册'

      // 返回 true 或不返回表示验证成功
      return true
    }
  })

添加全局验证器

import { addValidator } from '@/plugins/form-create-plugin'

// 添加自定义验证器
addValidator('phone', (value) => {
  return /^1[3-9]\d{9}$/.test(value)
})

// 使用
maker.input('phone', '手机号')
  .addValidate({
    type: 'phone',
    message: '手机号格式不正确'
  })

🔧 高级用法

动态控制

// 根据条件显示/隐藏字段
fapi.hidden('address', formData.type !== 'delivery')

// 根据条件禁用字段
fapi.disabled('discount', !formData.vip)

// 动态更新选项
const cities = ['北京', '上海', '广州']
fapi.updateRule('city', {
  options: cities.map(c => ({ label: c, value: c }))
})

表单联动

// 监听字段变化
this.rule = [
  maker.select('province', '省份')
    .options(provinces)
    .on('change', (value) => {
      // 更新城市选项
      const cities = getCitiesByProvince(value)
      this.fapi.updateRule('city', { options: cities })
    })
    .getRule(),

  maker.select('city', '城市')
    .options([])
    .getRule()
]

自定义组件

// 1. 创建自定义组件
// components/custom-input.vue
<template>
  <input :value="value" @input="$emit('input', $event.detail.value)" />
</template>

// 2. 在 FormItem 中注册
import CustomInput from '@/components/custom-input.vue'

// 3. 使用
maker.component('custom-input', 'field', '标题')

📝 完整示例

<template>
  <view class="container">
    <form-create 
      :rule="rule" 
      :option="option"
      @mounted="handleMounted"
    />

    <view class="btn-group">
      <button @click="submit" type="primary">提交</button>
      <button @click="reset" type="default">重置</button>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      fapi: null,
      rule: [],
      option: {
        autoValidate: true,
        validateOnBlur: true
      }
    }
  },

  created() {
    this.createRule()
  },

  methods: {
    createRule() {
      const { maker } = this.$formCreate

      this.rule = [
        // 基本信息
        maker.input('username', '用户名')
          .placeholder('请输入用户名')
          .required('用户名不能为空')
          .addValidate({ min: 3, max: 20, message: '用户名长度为3-20个字符' })
          .getRule(),

        maker.password('password', '密码')
          .placeholder('请输入密码')
          .required('密码不能为空')
          .addValidate({ min: 6, message: '密码不能少于6位' })
          .getRule(),

        maker.select('gender', '性别')
          .options([
            { label: '男', value: 'male' },
            { label: '女', value: 'female' }
          ])
          .required('请选择性别')
          .getRule(),

        maker.datePicker('birthday', '生日')
          .props({ end: '2020-12-31' })
          .getRule(),

        maker.radio('education', '学历')
          .options(['高中', '大专', '本科', '硕士', '博士'])
          .getRule(),

        maker.checkbox('hobby', '爱好')
          .options(['运动', '阅读', '旅游', '音乐', '游戏'])
          .value([])
          .getRule(),

        maker.slider('score', '评分')
          .value(60)
          .props({ min: 0, max: 100, showValue: true })
          .getRule(),

        maker.switch('agree', '同意用户协议')
          .value(false)
          .required('请同意用户协议')
          .getRule(),

        maker.upload('avatar', '头像')
          .value([])
          .props({
            maxCount: 1,
            text: '上传头像'
          })
          .getRule(),

        maker.textarea('intro', '个人简介')
          .props({ autoHeight: true })
          .getRule()
      ]
    },

    handleMounted(fapi) {
      this.fapi = fapi

      // 设置初始值
      fapi.setValue({
        username: '',
        gender: 'male',
        score: 80
      })
    },

    async submit() {
      try {
        const result = await this.fapi.validate()

        if (result.valid) {
          const formData = this.fapi.formData()
          console.log('表单数据:', formData)

          uni.showToast({
            title: '提交成功',
            icon: 'success'
          })
        }
      } catch (errors) {
        console.log('验证失败:', errors)
      }
    },

    reset() {
      this.fapi.resetFields()
      uni.showToast({
        title: '已重置',
        icon: 'none'
      })
    }
  }
}
</script>

<style>
.container {
  padding: 30rpx;
}

.btn-group {
  margin-top: 60rpx;
}

.btn-group button {
  margin-bottom: 20rpx;
}
</style>

🎨 样式定制

组件使用 rpx 单位,可以通过以下方式自定义样式:

// 设置表单项样式
maker.input('field', '标题')
  .className('custom-input')
  .style('margin-bottom: 40rpx;')

或者通过全局样式覆盖:

/* 修改输入框背景色 */
.fc-input__inner {
  background-color: #ffffff !important;
}

/* 修改标签颜色 */
.fc-form-item__label-text {
  color: #333333 !important;
}

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。