Skip to content

表单组件 中级版本

  • 在基础的版本上面增加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>