更新记录
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;
}