创建组件
components/test/index.vue
<template>
<el-form :model="formData" :rules='rules'>
// <!-- 具名插槽 -->
<slot name="header" />
<el-form-item
v-for="(item, index) in formItem"
:key="index"
:label="item.label"
:label-width="labelWith"
>
<template v-if="item.type === 'input'">
<el-input v-model="formData[item.field]" />
</template>
<template v-else-if="item.type === 'switch'">
<el-switch v-model="formData[item.field]" />
</template>
<template v-else>
<el-select v-model="formData[item.field]" @change="(e) => issueEvent(e, item.onChange)">
<el-option
v-for="opt in item.option"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</template>
</el-form-item>
// <!-- 具名插槽 -->
<slot name="footer" />
</el-form>
</template>
<script>
export default {
props: {
labelWith: {
type: String,
default: '100px'
},
formData: {
type: Object,
default: () => {}
},
formItem: {
type: Array,
default: () => []
}
},
created() {
console.log(this.formData, 'formData')
},
methods: {
// 重点在issueEvent函数,可以给事件绑定一个空函数避免报错,如果有外部传入的自定义函数则返回这个函数
/* 组件内函数负责分发表单项事件 */
issueEvent(value, mouseEvent) {
if (mouseEvent) {
return mouseEvent(value)
}
}
}
}
</script>
<style lang="scss" scoped></style>
表单项数据配置
export default {
formItem: [
{
type: 'input',
label: '颜色',
field: 'color',
prop: 'color',
rule: [
{ required: true, message: '请输入颜色', trigger: ['blur', 'change'] },
{ validator: (rule, value, callback) => {
if (value !== sessionStorage.getItem('hobbies')) {
callback(new Error('两次输入内容不一致'))
} else {
callback()
}
}
}
]
},
{
type: 'select',
label: '选择大小',
field: 'size',
prop: 'size',
option: [
{ label: 'S', value: '0' },
{ label: 'M', value: '1' }
],
onChange: (val) => { // 传入事件
console.log(val, 'val123')
},
rule: [
{ required: true, message: '请选择大小', trigger: ['blur', 'change'] }
]
},
{
type: 'input',
label: '爱好',
field: 'hobbies',
prop: 'hobbies',
rule: [
{ required: true, message: '请输入爱好', trigger: ['blur', 'change'] }
]
},
{
type: 'switch',
label: '开关',
field: 'state'
},
{
type: 'select',
label: '选择版本',
field: 'version',
option: [
{ label: '1.1', value: '0' },
{ label: '2.1', value: '1' }
]
}
]
}
使用组件
注意:必须把表单项要绑定的数据变成响应式数据,使用
this.$set(object, propertyName, value)
- object:要添加属性的目标对象。
- propertyName:要添加的属性的名称。
- value:要设置的属性值。
<template>
<MyTest :form-data="formData" :form-item="formItem" :rules='rules'>
<template #header>新增客户</template>
<template #footer>
<el-button type="primary" @click="submit">确定</el-button>
<el-button>取消</el-button>
</template>
</MyTest>
</template>
<script>
import formConfig from '@/config/test/testConfig'
import MyTest from '@/components/test/index.vue'
export default {
components: {
MyTest
},
data() {
return {
formData: {}, // 表单数据
formItem: formConfig.formItem ?? [], // ?? 表示空值合并操作符
rules: {}
}
},
watch: {
'formData.hobbies'(newValue, oldValue) {
console.log(newValue)
sessionStorage.setItem('hobbies', newValue) // 存入浏览器会话,用于自定义校验
}
},
created() {
this.formItem.forEach((item) => {
/**
* 使用了 Vue 实例的 $set 方法来确保 formData 对象的属性是响应式的。
* $set 方法是 Vue 2 中用来向响应式对象添加一个属性并确保这个新属性同样是响应式的。
*/
this.$set(this.formData, item.field, item.type === 'switch' ? false : '')
this.$set(this.rules, item.prop, item.rule) // 动态添加表单规则
})
},
methods: {
submit() {
console.log(this.formData, 'formData')
}
}
}
</script>
<style lang="scss" scoped></style>
封装 el-select
由于el-select
的option数据是异步请求过来的
所以要特殊处理下
表单项数据配置
import { getDepartmentList } from '@/api/department'
// 返回一个Promise,该Promise在解析时返回一个包含formItem的对象
export default async function getFormItem() {
const res = await getDepartmentList()
const departmentList = res.data
return (
[
{
type: 'select',
label: '部门',
field: 'departmentId',
option: departmentList.map(department => ({ // 注意:这里假设departmentList是一个数组,并且每个元素都有一个可以显示的属性(比如name)
label: department.name, // 根据实际情况修改
value: department.id // 根据实际情况修改
}))
}
])
}
使用组件
<template>
<my-form :form-data="formData" :form-item="formItem" />
</ template>
<script>
data() {
return {
formData: {}, // 表单数据
// formItem: commonConfig.formItem ?? [] // ?? 表示空值合并操作符
formItem: []
}
},
async created() {
this.formItem = await getFormItem()
console.log(this.formItem, 'formItem')
this.formItem.forEach((item) => {
/**
* 使用了 Vue 实例的 $set 方法来确保 formData 对象的属性是响应式的。
* $set 方法是 Vue 2 中用来向响应式对象添加一个属性并确保这个新属性同样是响应式的。
*/
this.$set(this.formData, item.field, '')
})
},
</ script>