Vue实现动态表单生成功能详解
动态表单是现代Web应用中常见的需求,它允许根据不同的业务场景或用户权限动态生成表单字段。本文将详细介绍如何使用Vue.js实现一个灵活的动态表单生成功能。
功能需求
我们需要实现一个表单系统,能够:
- 根据JSON配置动态渲染表单
- 支持多种表单字段类型(文本、数字、选择器等)
- 实现表单验证
- 支持动态添加/删除表单字段
实现步骤
1. 项目初始化
首先创建一个Vue项目(本文以Vue 3为例):
npm init vue@latest dynamic-form
cd dynamic-form
npm install
2. 定义表单配置数据结构
在src目录下创建formConfig.js,定义表单配置:
export const formConfig = {
title: '用户信息表单',
fields: [
{
type: 'text',
label: '姓名',
model: 'name',
required: true,
placeholder: '请输入姓名',
validation: {
pattern: '^[\\u4e00-\\u9fa5]{2,4}$',
message: '请输入2-4个中文字符'
}
},
{
type: 'number',
label: '年龄',
model: 'age',
min: 18,
max: 100
},
{
type: 'select',
label: '性别',
model: 'gender',
options: [
{ value: 'male', label: '男' },
{ value: 'female', label: '女' }
]
},
// 更多字段...
]
}
3. 创建动态表单组件
创建src/components/DynamicForm.vue:
<template>
<div class="dynamic-form">
<h2>{{ config.title }}</h2>
<form @submit.prevent="handleSubmit">
<div v-for="field in config.fields" :key="field.model" class="form-field">
<!-- 文本输入框 -->
<div v-if="field.type === 'text'">
<label :for="field.model">{{ field.label }}</label>
<input
type="text"
:id="field.model"
v-model="formData[field.model]"
:placeholder="field.placeholder"
:required="field.required"
/>
<span v-if="errors[field.model]" class="error">{{ errors[field.model] }}</span>
</div>
<!-- 数字输入框 -->
<div v-if="field.type === 'number'">
<label :for="field.model">{{ field.label }}</label>
<input
type="number"
:id="field.model"
v-model.number="formData[field.model]"
:min="field.min"
:max="field.max"
/>
</div>
<!-- 下拉选择框 -->
<div v-if="field.type === 'select'">
<label :for="field.model">{{ field.label }}</label>
<select :id="field.model" v-model="formData[field.model]">
<option
v-for="option in field.options"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</option>
</select>
</div>
<!-- 可以继续添加其他类型的表单字段 -->
</div>
<button type="submit">提交</button>
</form>
</div>
</template>
<script>
import { reactive, watch } from 'vue'
export default {
props: {
config: {
type: Object,
required: true
}
},
setup(props) {
// 初始化表单数据
const formData = reactive({})
const errors = reactive({})
// 根据配置初始化表单数据
props.config.fields.forEach(field => {
formData[field.model] = field.defaultValue || ''
})
// 表单验证
const validateField = (field) => {
if (field.required && !formData[field.model]) {
errors[field.model] = '此字段为必填项'
return false
}
if (field.validation && field.validation.pattern) {
const regex = new RegExp(field.validation.pattern)
if (!regex.test(formData[field.model])) {
errors[field.model] = field.validation.message || '格式不正确'
return false
}
}
delete errors[field.model]
return true
}
// 监听表单数据变化进行验证
props.config.fields.forEach(field => {
watch(() => formData[field.model], () => {
validateField(field)
})
})
// 提交表单
const handleSubmit = () => {
let isValid = true
props.config.fields.forEach(field => {
if (!validateField(field)) {
isValid = false
}
})
if (isValid) {
console.log('表单提交:', formData)
// 这里可以触发提交事件或调用API
} else {
console.log('表单验证未通过')
}
}
return {
formData,
errors,
handleSubmit
}
}
}
</script>
<style scoped>
.dynamic-form {
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
.form-field {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
}
input, select {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
.error {
color: red;
font-size: 12px;
display: block;
margin-top: 5px;
}
button {
background: #42b983;
color: white;
border: none;
padding: 10px 15px;
cursor: pointer;
margin-top: 10px;
}
button:hover {
background: #369f6b;
}
</style>
4. 使用动态表单组件
在App.vue中使用我们的动态表单组件:
<template>
<DynamicForm :config="formConfig" />
</template>
<script>
import DynamicForm from './components/DynamicForm.vue'
import { formConfig } from './formConfig'
export default {
components: {
DynamicForm
},
data() {
return {
formConfig
}
}
}
</script>
功能扩展
1. 动态添加/删除字段
在DynamicForm.vue中添加方法:
const addField = () => {
const newField = {
type: 'text',
label: '新字段',
model: `field_${Date.now()}`,
placeholder: '请输入内容'
}
props.config.fields.push(newField)
formData[newField.model] = ''
}
const removeField = (index) => {
const field = props.config.fields[index]
delete formData[field.model]
props.config.fields.splice(index, 1)
}
2. 支持更多字段类型
可以扩展支持更多字段类型,如:
// 复选框
<div v-if="field.type === 'checkbox'">
<label>
<input
type="checkbox"
v-model="formData[field.model]"
/>
{{ field.label }}
</label>
</div>
// 单选按钮组
<div v-if="field.type === 'radio'">
<label>{{ field.label }}</label>
<div v-for="option in field.options" :key="option.value">
<label>
<input
type="radio"
:value="option.value"
v-model="formData[field.model]"
/>
{{ option.label }}
</label>
</div>
</div>

浙公网安备 33010602011771号