表单组件 中级版本
- 在基础的版本上面增加el-select - el-option组件等等
(最重要) 表单的数据结构
interfaces/chooseForm/rules
- 请参照基础版本的代码
interfaces/chooseForm/type
ts
// 引入验证规则
import { type RuleItem } from './rules'
// 引入css style类型
import { type CSSProperties } from 'vue'
// 表单每一项的配置选项
export interface FormOptions {
// 表单显示的元素
// 表单项显示的元素
type:
| 'cascader'
| 'checkbox'
| 'checkbox-group'
| 'checkbox-button'
| 'color-picker'
| 'date-picker'
| 'input'
| 'input-number'
| 'radio'
| 'radio-group'
| 'radio-button'
| 'rate'
| 'select'
| 'option'
| 'slider'
| 'switch'
| 'time-picker'
| 'time-select'
| 'transfer'
| 'upload'
| 'editor'
// 表单项的值
value: any
// 表单的表示
prop: string
// 表单项的label
label?: string
// 表单项的验证规则
rules?: RuleItem[]
// 表单项的占位符
placeholder?: string
// 表单元素特有的属性
attrs?: {
// css样式
style?: CSSProperties
clearable?: boolean
showPassword?: boolean
disabled?: boolean
}
// 表单项的子元素类似于select的option,checkbox等等
children?: FormOptions[]
}
自己封装的表单组件
- components/chooseForm/index.vue
vue
<template>
<!--改变后不需要立即验证-->
<el-form v-if="model" v-bind="$attrs" :model="model" :rules="rules" :validate-on-rule-change="false">
<template v-for="(item, index) in options" :key="index">
<!--非checkbox.radio 之类的开始-->
<el-form-item :prop="item.prop" :label="item.label" v-if="!item.children || !item.children!.length">
<component
:placeholder="item.placeholder"
:is="`el-${item.type}`"
v-bind="item.attrs"
v-model="model[item.prop!]"
></component>
</el-form-item>
<!--非checkbox,radio之类的结束-->
<!--有子元素类似checkbox,radio 之类的开始-->
<el-form-item v-if="item.children && item.children.length" :prop="item.prop" :label="item.label">
<component
:placeholder="item.placeholder"
v-bind="item.attrs"
:is="`el-${item.type}`"
v-model="model[item.prop!]"
>
<component
v-for="(child, i) in item.children"
:key="i"
:is="`el-${child.type}`"
:label="child.label"
:value="child.value"
></component>
</component>
</el-form-item>
<!--有子元素类似 checkbox,radio之类的结束-->
</template>
</el-form>
</template>
<script setup lang="ts">
import { type PropType, ref, onMounted, watch } from 'vue'
import { type FormOptions } from '@/interfaces/chooseForm/type'
let props = defineProps({
options: {
type: Array as PropType<FormOptions[]>,
required: true
}
})
// 最后的结果应该就是 {username: '', password: ''}
// rules: { username: [{ required: true, message: '请输入用户名', trigger: 'blur' }] }
let model = ref<any>({})
let rules = ref<any>({})
// 赋值数据属性和验证规则
let setRulesAndValue = () => {
let m: any = {}
let r: any = {}
props.options.map((item: FormOptions) => {
m[item.prop!] = item.value
r[item.prop!] = item.rules
})
model.value = JSON.parse(JSON.stringify(m))
rules.value = JSON.parse(JSON.stringify(r))
console.log(model.value)
console.log(rules.value)
}
onMounted(() => {
setRulesAndValue()
})
// 监听父组件传递进来的options
watch(
() => {
return props.options
},
() => {
setRulesAndValue()
},
{
immediate: true
}
)
</script>
<style scoped></style>
父元素调用
vue
<template>
<div>
<YJ-choose-form :options="options" label-width="120px"></YJ-choose-form>
</div>
</template>
<script setup lang="ts">
import { type FormOptions } from '@/interfaces/chooseForm/type'
let options: FormOptions[] = [
{
type: 'input',
value: '',
label: '用户名',
prop: 'username',
placeholder: '请输入用户名',
attrs: {
clearable: true
}
},
{
type: 'input',
value: '',
label: '密码',
prop: 'password',
placeholder: '请输入密码',
rules: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 15, message: '密码在6-15位之间', trigger: 'blur' }
],
attrs: {
showPassword: true,
clearable: true
}
},
{
type: 'select',
value: '',
label: '职位',
prop: 'zhiwei',
placeholder: '请选择职位',
rules: [{ required: true, message: '职位不能为空', trigger: 'blur' }],
children: [
{
type: 'option',
value: '1',
label: '经理',
prop: 'options_id_1'
},
{
type: 'option',
value: '2',
label: '主管',
prop: 'options_id_2'
},
{
type: 'option',
value: '3',
label: '员工',
prop: 'options_id_3'
}
],
attrs: {
style: {
width: '150px'
}
}
},
{
type: 'checkbox-group',
value: [],
label: '爱好',
prop: 'hobby',
rules: [{ required: true, message: '爱好不能为空', trigger: 'blur' }],
children: [
{
type: 'checkbox',
value: '1',
label: '篮球',
prop: 'options_id_1'
},
{
type: 'checkbox',
value: '2',
label: '足球',
prop: 'options_id_2'
},
{
type: 'checkbox',
value: '3',
label: '排球',
prop: 'options_id_3'
}
]
},
{
type: 'radio-group',
value: '',
label: '作业',
prop: 'zuoye',
rules: [{ required: true, message: '作业不能为空', trigger: 'blur' }],
children: [
{
type: 'radio',
value: '1',
label: '语文',
prop: 'options_id_1'
},
{
type: 'radio',
value: '2',
label: '数学',
prop: 'options_id_2'
},
{
type: 'radio',
value: '3',
label: '外语',
prop: 'options_id_3'
}
]
}
]
</script>
<style scoped></style>