Skip to content

组件思路

  1. 用法:就是和原来el-form一样,api基本一致,就是把本来绑定在el-form的属性绑定在此组件上,把本来绑定在el-form-item上的属性通过formOption属性以数组的形式传入,数组内每个对象对应着每一列的el-form-item,上手较快。
  2. 当然也内置了一些按钮配置项,输入校验配置项,自定义切换输入模式和查看你模式等等。

例子

基本使用

formOption 属性就是我们form的配置项,数组内的每一个对象代表着一个form输入节点,所有对象内的属性都会传递到el-form-item上,所以与原element-plus属性全部相同。
type: 这个属性代表输入框的类型,其参考按钮类型
inputProps:每一个对象上的按钮绑定属性,都在每一个对象上的这个对象内,其内部属性会全部传递到你的输入框上。
option: 所有的选择列表数据都放在formOptionoption属性内,并且都已经转为:label: 代表显示的文字,value:代表值。
value: 当配置项对象内传入此值时,就是代表覆盖值,则其会直接覆盖原prop 对应传入象内的值。
defaultSelect: 当type: 'select',也就是单选框的时候,defaultSelect可以传入索引,代表默认选择的列。

<template>
    <FpiElForm
        v-model="formData"
        :form-option="formOption"
    />
</template>

<script lang="ts" setup>
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'
import { reactive, toRefs } from 'vue'

const data = reactive({
    formOption: [
        {
            label: '输入框',
            type: 'input',
            size: 'small',
            prop: 'input1',
            value: '88',
            inputProps: {
                placeholder: '测试',
                disabled: true,
            }
        },
        {
            label: '数字输入框',
            type: 'input',
            value: null,
            prop: 'inputNum',
            inputProps: {
                clearable: true,
                placeholder: '测试',
                oninput: () => {
                    console.log('object')
                }
            }

        },
        {
            label: '密码输入框',
            type: 'input',
            prop: 'inputPass',
            value: '5456415646768',
            inputProps: {
                showPassword: true,
                type: 'password',
                clearable: true,
                placeholder: '测试',
            }
        },
        {
            label: 'select输入',
            type: 'select',
            prop: 'select',
            defaultSelect: 0,
            option: [
                { label: 'Zone one', value: 'shanghai' },
                { label: 'Zone two', value: 'beijing' },
                { label: 'Zone three', value: 'hangzhou' },
            ],
            inputProps: {
                clearable: true,
            }
        },
        {
            label: 'col 时间输入',
            col: [
                {
                    span: 11,
                    type: 'date-picker',
                    prop: 'date1',
                    inputProps: {
                        type: 'date',
                        placeholder: 'Pick a date',
                    }

                },
                {
                    type: 'dom',
                    span: 2,
                    vHtml: () => {
                        return '<div style="color: #6b7280;text-align:center;width: 100%;">-</div>'
                    }
                },
                {
                    span: 11,
                    type: 'time-picker',
                    prop: 'date2',
                    inputProps: {
                        style: 'width: 100%;',
                        placeholder: 'Pick a time',
                    }
                }
            ]
        },
        {
            label: '滑块',
            type: 'switch',
            prop: 'delivery',
            value: true
        },
        {
            label: '多选',
            type: 'checkbox',
            prop: 'checkbox1',
            value: [],
            option: [
                { label: 'Zone one', value: 'shanghai1' },
                { label: 'Zone two', value: 'shanghai2' },
                { label: 'Zone three', value: 'shanghai3' },
            ]
        },
        {
            label: '单选',
            type: 'radio',
            prop: 'radio',
            option: [
                { label: 'Zone one', value: 'shanghai1' },
                { label: 'Zone two', value: 'shanghai2' },
                { label: 'Zone three', value: 'shanghai3' },
            ]
        },
        {
            label: 'textarea输入框',
            type: 'input',
            prop: 'textarea1',
            inputProps: {
                placeholder: '测试',
                type: 'textarea'
            }

        }
    ] as formItemTs[],
    formData: {
        input1: '',
        inputNum: '' as string | number,
        inputPass: '',
        select: 'shanghai',
        selId: '',
        date1: '',
        date2: '',
        delivery: '',
        checkbox1: '',
        radio: '',
        textarea1: '',
        slot1: ''
    }

})

const { formOption, formData } = toRefs(data)
</script>
显示代码

表单按钮

表单的按钮默认会有一个提交和取消按钮,分别对应submitcancel方法,前者会自动进行表单校验,后者会字段重置表单。如果有设置value则会自动恢复到其对应的值。
所有方法的入参都是组件本身的实例。
formBtnOption: 通过传入此项可以进行自定义的设置表格事件。
isShowBtnBox: 可以设置 是否显示按钮。

<template>
    <FpiElForm
        v-model="formData"
        :form-option="formOption"
        :form-btn-option="formBtnOption"
        @submit="submit"
        @cancel="cancel"
    />
</template>

<script lang="ts" setup>
import type { btnOptionTs, formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'
import { onMounted, reactive, toRefs } from 'vue'

const data = reactive({
    formOption: [
        {
            label: '数字输入框',
            type: 'input',
            value: null,
            prop: 'inputNum',
            rules: 'unNull,number',
            inputProps: {
                inputLimit: 'number',
                clearable: true,
                placeholder: '测试',
                onInput: (e) => {
                    console.log(e)
                }
            }
        },
        {
            label: 'select输入',
            type: 'select',
            prop: 'select',
            defaultSelect: 0,
            rules: 'select',
            option: [
                { label: 'Zone one', value: 'shanghai' },
                { label: 'Zone two', value: 'beijing' },
                { label: 'Zone three', value: 'hangzhou' },
            ],
            inputProps: {
                onVisibleChange: (e) => {
                    console.log(e, 'e')
                },
                clearable: true,
            }
        },
        {
            label: '自定义',
            type: 'input',
            value: null,
            prop: 'radio',
            rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
            inputProps: {
                clearable: true,
                placeholder: '测试',
            }
        },
    ] as formItemTs[],
    formData: {
        inputNum: '' as string | number,
        radio: '',
        select: ''
    },
    formBtnOption: [
        {
            type: 'primary',
            label: '提交',
            onClick: 'submit'
        },
        {
            label: '取消',
            onClick: 'cancel'
        }
    ] as btnOptionTs[]

})

onMounted(() => {
    data.formBtnOption = [
        {
            type: 'primary',
            label: '提交',
            onClick: 'submit',
            onDblclick: () => {
                console.log('ondblclick')
            }
        },
        {
            type: 'success',
            label: '自定义取消按钮',
            onClick: customMethods
        },
        {
            label: '取消',
            onClick: 'cancel'
        }
    ]
    data.formOption[0].label = '改变的label'
})
const submit = (formRef: any, e: Event) => {
    console.log('表单提交回调', formRef, e)
}
const cancel = (formRef: any, e: Event) => {
    console.log('表单取消回调', formRef, e)
}
const customMethods = (formRef: any, e: Event) => {
    formRef && formRef.resetFields()
    console.log('自定义按钮回调:', formRef, e)
}
const { formOption, formData, formBtnOption } = toRefs(data)
</script>
显示代码

表格校验

rules: formOption每个对象内传入rules就可以产生多种校验规则。
组件内部内置了一些rule的语法糖,内部含有email, date, select, unNull, number, phone, checkbox, ,只需要转入对应字符串,或者,分隔组合字符串,或者以此作为key,值为 string 类型来替换其默认的错误提示 message。详情请查看 rule语法糖
当然也可以自定义传入规则,或者在FpiElForm 上传入rules规则。
trigger form传入此属性用于设置整个form 的 语法糖默认的校验触发时机 change| blur

<!--
 * @Author: mjh
 * @Date: 2023-04-11 11:08:41
 * @LastEditors: mjh
 * @LastEditTime: 2023-04-22 23:35:14
 * @Description:
-->
<template>
    <FpiElForm
        v-model="formData"
        :form-option="formOption"
    />
</template>

<script lang="ts" setup>
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'
import { reactive, toRefs } from 'vue'

const data = reactive({
    formOption: [
        {
            label: '输入框',
            type: 'input',
            size: 'small',
            prop: 'input1',
            rules: 'unNull',
            value: '88',
            inputProps: {
                placeholder: '测试',
                disabled: true,
            }
        },
        {
            label: '数字输入框',
            type: 'input',
            value: null,
            prop: 'inputNum',
            rules: 'unNull,number',
            inputProps: {
                inputLimit: 'number',
                clearable: true,
                placeholder: '测试',
            }
        },
        {
            label: 'select输入',
            type: 'select',
            prop: 'select',
            defaultSelect: 0,
            rules: 'select',
            option: [
                { label: 'Zone one', value: 'shanghai' },
                { label: 'Zone two', value: 'beijing' },
                { label: 'Zone three', value: 'hangzhou' },
            ],
            inputProps: {
                clearable: true,
            }
        },
        {
            label: '自定义提示',
            type: 'input',
            value: null,
            prop: 'format',
            rules: { unNull: '自定义的message' },
            inputProps: {
                inputLimit: 'number',
                clearable: true,
                placeholder: '测试',
            }
        },
        {
            label: '数组rule',
            type: 'input',
            value: null,
            prop: 'radio',
            rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
            inputProps: {
                clearable: true,
                placeholder: '测试',
            }
        },
    ] as formItemTs[],
    formData: {
        input1: '',
        inputNum: '' as string | number,
        format: '',
        radio: '',
        select: ''
    }

})

const { formOption, formData } = toRefs(data)
</script>
显示代码

输入框的使用

isFocus: 该属性可以让默认获取焦点。
inputLimit: 输入限制属性是一个语法糖,可以帮我们方便的完成输入的限制功能,当然也支持回调函数形式,进行自定义设置。详情输入限制

<!--
 * @Author: mjh
 * @Date: 2023-04-11 11:08:41
 * @LastEditors: mjh
 * @LastEditTime: 2023-04-22 23:35:30
 * @Description:
-->
<template>
    <FpiElForm
        v-model="formData"
        :form-option="formOption"
    />
</template>

<script lang="ts" setup>
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

import { reactive, toRefs } from 'vue'

const data = reactive({
    formOption: [
        {
            label: '输入框',
            type: 'input',
            size: 'small',
            prop: 'input1',
            value: '88',
            inputProps: {
                placeholder: '测试',
                disabled: true,
            }
        },
        {
            label: '数字输入框',
            type: 'input',
            prop: 'inputNum',
            inputProps: {
                inputLimit: 'number',
                clearable: true,
                isFocus: true,
                placeholder: '测试',
            }
        },
        {
            label: '负数输入框',
            type: 'input',
            prop: 'radio',
            inputProps: {
                inputLimit: 'negative-number',
                clearable: true,
                placeholder: '测试',
            }
        },
    ] as formItemTs[],
    formData: {
        input1: '',
        inputNum: '' as string | number,
        radio: '',
        select: ''
    }

})

const { formOption, formData } = toRefs(data)
</script>
显示代码

col的使用

col: 属性可以让我们自定义一行内多个按钮的大小以及间隔,span就代表这个按钮在这一行占的大小,沾满是24
gutter: 代表间隔,默认是 0
vHtml: 当设置 type: 'dom' 时,此行就可以使用此属性传入一个html的字符串实现自定义中间间隔内容。

WARNING

注意:col内的input最好不要设置 label 属性不然会出现 input的空间被 label占去大半的情况, 如果想设置多个请看下一个例子。

<!--
 * @Author: mjh
 * @Date: 2023-07-05 19:39:36
 * @LastEditors: mjh
 * @LastEditTime: 2023-07-26 10:49:53
 * @Description:
-->
<template>
    <FpiElForm
        v-model="formData"
        :form-option="formOption"
    />
</template>

<script lang="ts" setup>
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

import { reactive, toRefs } from 'vue'

const data = reactive({
    formOption: [
        {
            label: 'col 时间输入',
            col: [
                {
                    span: 11,
                    type: 'date-picker',
                    prop: 'date1',
                    inputProps: {
                        type: 'date',
                        placeholder: 'Pick a date',
                    }

                },
                {
                    type: 'dom',
                    span: 2,
                    vHtml: () => {
                        return '<div style="color: #6b7280;text-align:center;width: 100%;">-</div>'
                    }
                },
                {
                    span: 11,
                    type: 'time-picker',
                    prop: 'date2',
                    inputProps: {
                        style: 'width: 100%;',
                        placeholder: 'Pick a time',
                    }
                }
            ]
        },
        {
            label: 'col 时间输入',
            gutter: 20,
            col: [
                {
                    span: 8,
                    type: 'input',
                    prop: 'input1',
                    inputProps: {
                        clearable: true,
                        placeholder: '测试',
                    }
                },
                {
                    span: 8,
                    type: 'input',
                    prop: 'radio',
                    inputProps: {
                        inputLimit: 'negative-number',
                        clearable: true,
                        placeholder: '测试',
                    }
                },
            ]
        }

    ] as formItemTs[],
    formData: {
        input1: '',
        inputNum: '' as string | number,
        radio: '',
        select: '',
        date1: '',
        date2: ''
    }

})

const { formOption, formData } = toRefs(data)
</script>
显示代码

col一行多个label

TIP

此项需要配合样式设置 el-form-item__content的样式为 margin-left: 0 才能实现,不然左边会有很多的空隙。

<template>
    <div class="form-box-test">
        <FpiElForm
            ref="ruleFormRef"
            v-model="formData"
            :form-option="formOption"
            label-width="160px"
        />
    </div>
</template>

<script lang="ts" setup>
// ************使用col时 底部的样式设置很重要哦 ************
import { reactive, toRefs } from 'vue'
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

const data = reactive({
    formOption: [
        {
            col: [
                {
                    label: '企业名称:',
                    span: 12,
                    type: 'input',
                    prop: 'input1',
                    rules: 'unNull',
                    inputProps: {
                        placeholder: '请选择企业',
                        clearable: true,

                    }
                },
                {
                    span: 12,
                    label: '企业生产状态:',
                    type: 'input',
                    value: null,
                    prop: 'inputNum',
                    rules: 'unNull,number',
                    inputProps: {
                        inputLimit: 'number',
                        clearable: true,
                        placeholder: '',
                    }
                },
            ]
        },
        {
            col: [
                {
                    span: 12,
                    label: '排口名称:',
                    type: 'input',
                    showPassword: true,
                    prop: 'inputPass',
                    rules: 'unNull',
                },
                {
                    span: 12,
                    label: '排口编号:',
                    type: 'input',
                    showPassword: true,
                    prop: 'inputPass',
                    rules: 'unNull',
                    inputProps: {
                        clearable: true,
                        disabled: true,
                    }
                },
            ]
        },
        {
            col: [
                {
                    label: '邮箱:',
                    type: 'input',
                    prop: 'curEmails',
                    rules: 'email',
                },
            ]
        },
        {
            label: '经纬度:',
            required: true,
            gutter: 15,
            col: [
                {
                    span: 5,
                    type: 'input',
                    prop: 'long',
                    rules: 'unNull',
                    inputProps: {
                        clearable: true,
                    }
                },
                {
                    span: 5,
                    type: 'input',
                    prop: 'lat',
                    rules: 'unNull',
                    inputProps: {
                        clearable: true,

                    }
                }
            ]
        },
        {
            col: [
                {
                    label: '是否参与有效率计算:',
                    type: 'radio',
                    prop: 'delivery',
                    value: true,
                    option: [
                        { label: '', value: true },
                        { label: '', value: false },
                    ]
                }
            ]
        },
    ] as formItemTs[],
    formData: {
        input1: '',
        inputNum: '',
        inputPass: '',
        delivery: '',
        curEmails: '',
        lat: '',
        long: ''
    },
})

const { formOption, formData } = toRefs(data)
</script>

<style lang="scss" scoped>
.form-box-test {
    ::v-deep(.el-form-item__content) {
        margin-left: 0 !important;
    }
}
</style>

显示代码

自定义rules

这个例子中展示了如何使用自定义验证规则来完成密码的二次验证。

本例还使用status-icon属性为输入框添加了表示校验结果的反馈图标。

<!--
 * @Author: mjh
 * @Date: 2022-08-19 09:31:37
 * @LastEditors: mjh
 * @LastEditTime: 2023-04-11 11:21:58
 * @Description:
-->
<template>
    <FpiElForm
        ref="ruleFormRef"
        v-model="formData"
        :form-option="itemList"
        status-icon
    />
</template>

<script lang="ts" setup name="FpiForm">
import type { formItemTs, fpiFormTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'
import { reactive, ref, toRefs } from 'vue'

const ruleFormRef: any = ref<fpiFormTs>()
const checkAge = (rule: any, value: any, callback: any) => {
    if (!value)
        return callback(new Error('Please input the age'))

    setTimeout(() => {
        if (!Number.isInteger(value))
            callback(new Error('Please input digits'))

        else if (value < 18)
            callback(new Error('Age must be greater than 18'))

        else
            callback()
    }, 1000)
}
const validatePass = (rule: any, value: any, callback: any) => {
    if (!ruleFormRef.value) return
    if (value === '') {
        callback(new Error('Please input the password'))
    }
    else {
        if (data.formData.checkPass !== '')
            ruleFormRef.value.validateField('checkPass', () => null)

        callback()
    }
}
const validatePass2 = (rule: any, value: any, callback: any) => {
    if (!ruleFormRef.value) return
    if (value === '')
        callback(new Error('Please input the password again'))

    else if (value !== data.formData.pass)
        callback(new Error('Two inputs don\'t match!'))

    else
        callback()
}
const data = reactive({
    itemList: [
        {
            label: '第一次输入密码',
            type: 'input',
            prop: 'pass',
            rules: [{ validator: validatePass, trigger: 'blur' }] as const,
            inputProps: {
                type: 'password',
                autocomplete: 'off'
            }
        },
        {
            label: '第二次输入密码',
            type: 'input' as const,
            prop: 'checkPass',
            rules: [{ validator: validatePass2, trigger: 'blur' }],
            inputProps: {
                type: 'password',
                autocomplete: 'off'
            }
        },
        {
            label: 'age年龄',
            type: 'input' as const,
            prop: 'age',
            inputProps: {
                inputLimit: 'number'
            },
            rules: [{ validator: checkAge, trigger: 'blur' }],
        }
    ] as formItemTs[],
    formData: {
        pass: '',
        checkPass: '',
        age: ''
    }
})

const { itemList, formData } = toRefs(data)
</script>

显示代码

添加/删除表单项

除了一次通过表单组件上的所有验证规则外. 您也可以动态地通过验证规则或删除单个表单字段的规则。
prop: 此属性可以以字符串的形式通过.分割获取到对象内各种位置的属性,所以不用担心对象多级嵌套的情况。

<template>
    <div class="control-btn">
        <ElButton type="primary" @click="addDomain()">
            增加表单
        </ElButton>
        <ElButton @click="removeDomain()">
            删除末尾
        </ElButton>
    </div>
    <div class="form-box">
        <FpiElForm v-model="formData" :form-option="itemList" />
    </div>
</template>

<script lang="ts" setup>
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

import { h, reactive, toRefs } from 'vue'
import { ElButton } from 'element-plus'
const data = reactive({
    itemList: [
        {
            label: '输入框',
            type: 'input',
            prop: 'email',
            inputProps: {
                placeholder: '测试',
            },
            rules: [
                {
                    required: true,
                    message: 'Please input email address',
                    trigger: 'blur',
                },
                {
                    type: 'email',
                    message: 'Please input correct email address',
                    trigger: ['blur', 'change'],
                }
            ]
        },
        {
            label: '动态输入框',
            gutter: 20,
            col: [
                {
                    span: 12,
                    type: 'input',
                    prop: 'domains.0.value',
                    inputProps: {
                        placeholder: '测试',
                    },
                    rules: 'unNull'
                },
                {
                    span: 4,
                    type: 'dom',
                    render: (index: number) => {
                        return h(
                            ElButton,
                            {
                                type: 'danger',
                                onClick: () => removeDomain(index)
                            },
                            { default: () => '删除' }
                        )
                    }
                }
            ]
        }
    ] as formItemTs[],
    formData: {
        email: '',
        domains: [
            {
                prop: 1,
                value: '',
            }
        ] as Array<any | null>
    }

})

const removeDomain = (index?: number) => {
    if (!data.formData.domains.length) return
    if (typeof index !== 'number') {
        data.itemList.pop()
        data.formData.domains.pop()
        return
    }
    data.itemList.splice(index, 1)
    data.itemList.forEach((item, index) => {
        item.col && (item.col[0].prop = `domains.${index - 1}.value`)
    })
    data.formData.domains.splice(index - 1, 1)
}

const addDomain = () => {
    data.formData.domains.push({
        prop: Date.now(),
        value: '123',
    })
    data.itemList.push({
        label: '动态输入框',
        gutter: 20,
        col: [
            {
                span: 12,
                type: 'input',
                prop: `domains.${data.formData.domains.length - 1}.value`,
                inputProps: {
                    placeholder: '测试',
                },
                rules: 'unNull'
            },
            {
                span: 4,
                type: 'dom',
                render: (index: number) => {
                    return h(
                        ElButton,
                        {
                            type: 'danger',
                            onClick: () => removeDomain(index)
                        },
                        { default: () => '删除' }
                    )
                }
            }
        ]
    } as formItemTs)
}

const { itemList, formData } = toRefs(data)
</script>

<style lang="scss" scoped>
.control-btn {
    width: fit-content;
    margin: 0 auto 15px;
}
</style>
显示代码

尺寸控制和对齐方式

根据你们的设计情况,来选择最佳的标签对齐方式。
通过设置 label-position 属性可以改变表单域标签的位置,可选值为 top、left, 当设为 top 时标签会置于表单域的顶部。
表单中的所有子组件都继承了该表单的 size 属性。 同样,formOption 也有一个 size 属性。 如果希望某个表单项或某个表单组件的尺寸不同于 Form 上的 size 属性,直接为这个表单项或表单组件设置自己的 size 属性即可。

<template>
    <div class="form-box">
        <div>
            <el-radio-group v-model="labelPosition" label="label position">
                <el-radio-button label="left">
                    Left
                </el-radio-button><el-radio-button label="right">
                    Right
                </el-radio-button><el-radio-button label="top">
                    Top
                </el-radio-button>
            </el-radio-group>
        </div>
        <br>
        <div>
            <el-radio-group v-model="inline" label="是否inline">
                <el-radio-button :label="true">
                    inline
                </el-radio-button><el-radio-button :label="false">
                    not-inline
                </el-radio-button>
            </el-radio-group>
        </div>
        <br>
        <div>
            <el-radio-group v-model="size" label="尺寸">
                <el-radio-button label="large">
                    large
                </el-radio-button><el-radio-button label="default">
                    default
                </el-radio-button><el-radio-button label="small">
                    small
                </el-radio-button>
            </el-radio-group>
        </div>
        <br>
        <FpiElForm
            v-model="formData"
            :form-option="formOption"
            :inline="inline"
            :label-position="labelPosition"
            :size="size"
        />
    </div>
</template>

<script lang="ts" setup>
import { reactive, toRefs } from 'vue'
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

const data = reactive({
    formOption: [
        {
            label: '输入框',
            type: 'input',
            size: 'small',
            prop: 'input1',
            inputProps: {
                placeholder: '测试',
                disabled: true,
            },
            value: '15',
            rules: 'unNull'
        },
        {
            label: '数字输入框',
            type: 'input',
            value: null,
            inputProps: {
                inputLimit: 'number',
                clearable: true,
                placeholder: '测试',
            },
            prop: 'inputNum',
            rules: 'unNull,number'
        },
        {
            label: '密码输入框',
            type: 'input',
            inputProps: {
                showPassword: true,
                type: 'password',
                clearable: true,
                placeholder: '测试',
            },
            prop: 'inputPass',
            rules: 'unNull'
        },
        {
            label: 'select输入',
            type: 'select',
            prop: 'selId',
            inputProps: {
                clearable: true,

            },
            defaultSelect: 0,
            option: [
                { label: 'Zone one', value: 'shanghai' },
                { label: 'Zone two', value: 'beijing' },
                { label: 'Zone three', value: 'hangzhou' },
            ]
        },
        {
            label: 'textarea输入框',
            type: 'input',
            prop: 'textarea1',
            inputProps: {
                placeholder: '测试',
                type: 'textarea'
            }
        }
    ] as formItemTs[],
    formData: {
        input1: '',
        inputNum: '',
        inputPass: '',
        selId: '',
        textarea1: '',
    },
    labelPosition: 'left' as const,
    inline: false,
    size: 'default' as const

})

const { formOption, formData, labelPosition, inline, size } = toRefs(data)
</script>
显示代码

插槽使用

slot:设置此属性可以开启自定义插槽input, 插槽名称就是此项对应的prop值。
labelSlot:设置此属性可以开启自定义插槽label,插槽名称就是此项对应的${prop}-label

<!--
 * @Author: mjh
 * @Date: 2023-04-11 11:08:41
 * @LastEditors: mjh
 * @LastEditTime: 2023-04-11 11:22:07
 * @Description:
-->
<template>
    <FpiElForm v-model="formData" :form-option="formOption">
        <template #slot1="scoped">
            <el-input v-model="(formData as any)[scoped.prop]" />
        </template>
        <template #inputPass-label>
            <span>插入label</span>
        </template>
        <template #slot2>
            <el-input v-model="formData.slot2" />
        </template>
        <template #input1>
            <el-input v-model="formData.input1" />
        </template>
    </FpiElForm>
</template>

<script lang="ts" setup>
import { reactive, toRefs } from 'vue'
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

const data = reactive({
    formOption: [
        {
            label: '密码输入框',
            type: 'input',
            labelSlot: true,
            prop: 'inputPass',
            rules: 'unNull',
            inputProps: {
                showPassword: true,
                type: 'password',
                clearable: true,
                placeholder: '测试',
            }
        },
        {
            label: '插槽输入',
            type: 'input',
            prop: 'slot1',
            slot: true,
            rules: 'unNull',
        },
        {
            col: [
                {
                    span: 12,
                    label: '插槽输入',
                    type: 'input',
                    prop: 'slot2',
                    slot: true,
                    rules: 'unNull',
                },
                {
                    span: 12,
                    label: '插槽输入2',
                    type: 'input',
                    prop: 'input1',
                    slot: true,
                    rules: 'unNull',
                }
            ]
        },
    ] as formItemTs[],
    formData: {
        inputPass: '',
        input1: '',
        slot1: '',
        slot2: ''
    }

})

const { formOption, formData } = toRefs(data)
</script>

<style lang="scss" scoped>
::v-deep(.el-form-item__content) {
    margin-left: 0 !important;
}
</style>
显示代码

一键切换文字显示

is-text:设置此属性可以开启文字显示模式,所有input输入框都会转化成文字,配合设置:form-btn-option="[]"隐藏按钮,用于查看模式。
表单配置项内的value属性会失效,不会替换掉显示的值。(当然也可以单独设置某一个option内的 { type: 'text' },设置为文本格式。)
样式:修改样式可以 使用 textStyle 或者 inputProps: { style: { ... } } 也可以 样式穿透 class fpi-el-form-text 自定义文本样式

<!--
 * @Author: mjh
 * @Date: 2023-04-08 10:10:19
 * @LastEditors: mjh
 * @LastEditTime: 2023-04-08 15:08:52
 * @Description:
-->
<template>
    <FpiElForm
        v-model="formData"
        :form-option="formOption"
        is-text
        :form-btn-option="[]"
    />
</template>

<script lang="ts" setup>
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

import { reactive, toRefs } from 'vue'

const data = reactive({
    formOption: [
        {
            label: '输入框:',
            type: 'input',
            size: 'small',
            prop: 'input1',
            value: '88',
            inputProps: {
                placeholder: '测试',
                disabled: true,
            }
        },
        {
            label: '数字输入框:',
            type: 'input',
            value: 1234,
            prop: 'inputNum',
            inputProps: {
                clearable: true,
                placeholder: '测试',
            }

        },
        {
            label: 'select输入:',
            type: 'select',
            prop: 'select',
            defaultSelect: 0,
            option: [
                { label: 'Zone one', value: 'shanghai' },
                { label: 'Zone two', value: 'beijing' },
                { label: 'Zone three', value: 'hangzhou' },
            ],
            inputProps: {
                clearable: true,
            }
        },
        {
            label: '多选:',
            type: 'checkbox',
            prop: 'checkbox1',
            value: [],
            option: [
                { label: 'Zone one', value: 'shanghai1' },
                { label: 'Zone two', value: 'shanghai2' },
                { label: 'Zone three', value: 'shanghai3' },
            ]
        },
        {
            label: '单选:',
            type: 'radio',
            prop: 'radio',
            option: [
                { label: 'Zone one', value: 'shanghai1' },
                { label: 'Zone two', value: 'shanghai2' },
                { label: 'Zone three', value: 'shanghai3' },
            ]
        },
        {
            label: 'textarea输入框:',
            type: 'input',
            prop: 'textarea1',
            inputProps: {
                placeholder: '测试',
                type: 'textarea'
            }

        }
    ] as formItemTs[],
    formData: {
        input1: 'test',
        inputNum: '123' as string | number,
        select: 'shanghai',
        checkbox1: ['shanghai1', 'shanghai2'],
        radio: 'shanghai1',
        textarea1: '测试文字测试文字测试文字测试文字测试文字测试文字测试文字',
    }

})

const { formOption, formData } = toRefs(data)
</script>
显示代码

input前后缀

type: 'input'时,其支持prepend,append,empty,suffixIcon,suffix,prefixIcon,prefix插槽,内部可以传入vue组件,或者h函数创建的dom节点等等。

<!--
 * @Author: mjh
 * @Date: 2022-11-28 09:47:53
 * @LastEditors: mjh
 * @LastEditTime: 2023-07-26 10:53:52
 * @Description:
-->
<template>
    <FpiElForm
        v-model="formData"
        :form-option="formOption"
    />
</template>

<script lang="ts" setup>
import { h, markRaw, reactive, toRefs } from 'vue'
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'
import { Calendar } from '@element-plus/icons-vue'
import FpiFrom11Com from './fpi-form11-com.vue'
// 当然你可以直接通过设置type = 'text' 设置单项的类型为文本
const data = reactive({
    formOption: [
        {
            label: '数字输入框',
            type: 'input',
            prop: 'inputNum',
            value: null,
            rules: 'unNull,number',
            inputProps: {
                append: h(
                    'div',
                    123
                ),
                suffixIcon: markRaw(Calendar),
                suffix: h(
                    markRaw(FpiFrom11Com),
                ),
                clearable: true,
                placeholder: '测试',
            }
        },
        {
            label: '密码输入框',
            type: 'input',
            labelSlot: true,
            prop: 'inputPass',
            rules: 'unNull',
            inputProps: {
                prefixIcon: markRaw(Calendar),
                showPassword: true,
                type: 'password',
                clearable: true,
                placeholder: '测试',
            }
        },
        {
            label: 'select输入',
            type: 'select',
            prop: 'selId',
            defaultSelect: 0,
            option: [],
            inputProps: {
                prefixIcon: h(
                    'div',
                    123
                ),
                empty: h(
                    'div',
                    '无数据111'
                ),
                clearable: true,
            }
        },
    ] as formItemTs[],
    formData: {
        input1: '1241213',
        inputNum: 12314141,
        inputPass: '1241213',
        selId: 'shanghai',
        radio: 'shanghai3',
        slot1: '父亲额',
        checkbox1: ['shanghai1', 'shanghai3']
    }

})

const { formOption, formData } = toRefs(data)
</script>

显示代码

表单分割线

设置isLine: true开启,可以设置 lineLabel 设置分割线文字,当然也可以使用 lineLabelStyle, lineStyle 来分别设置分割线的文字和分割线样式。

<template>
    <FpiElForm
        v-model="formData"
        :form-option="formOption"
    />
</template>

<script lang="ts" setup>
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

import { reactive, toRefs } from 'vue'
const data = reactive({
    formOption: [
        {
            isLine: true, // 是否是分割线
            lineLabel: '基础信息' // 分割线文字
        },
        {
            col: [
                {
                    label: '企业名称:',
                    span: 12,
                    type: 'input',
                    prop: 'input1',
                    rules: 'unNull',
                    inputProps: {
                        placeholder: '请选择企业',
                        clearable: true,

                    }
                },
                {
                    span: 12,
                    label: '企业:',
                    type: 'input',
                    value: null,
                    prop: 'inputNum',
                    rules: 'unNull,number',
                    inputProps: {
                        inputLimit: 'number',
                        clearable: true,
                        placeholder: '',
                    }
                },
            ]
        },
        {
            isLine: true, // 是否是分割线
            lineLabel: '基础信息', // 分割线文字
            lineLabelStyle: {
                color: 'red'
            }
        },
        {
            col: [
                {
                    span: 12,
                    label: '排口名称:',
                    type: 'input',
                    showPassword: true,
                    prop: 'inputPass',
                    rules: 'unNull',
                },
                {
                    span: 12,
                    label: '排口编号:',
                    type: 'input',
                    showPassword: true,
                    prop: 'inputPass',
                    rules: 'unNull',
                    inputProps: {
                        clearable: true,
                        disabled: true,
                    }
                },
            ]
        },
        {
            isLine: true, // 是否是分割线
            lineLabel: '基础信息', // 分割线文字
            lineStyle: {
                background: 'red'
            }
        },
        {
            col: [
                {
                    label: '邮箱:',
                    type: 'input',
                    prop: 'curEmails',
                    rules: 'email',
                },
            ]
        },
        {
            label: '经纬度:',
            required: true,
            gutter: 15,
            col: [
                {
                    span: 5,
                    type: 'input',
                    prop: 'log',
                    rules: 'unNull',
                    inputProps: {
                        clearable: true,
                    }
                },
                {
                    span: 5,
                    type: 'input',
                    prop: 'lat',
                    rules: 'unNull',
                    inputProps: {
                        clearable: true,

                    }
                }
            ]
        },
        {
            isLine: true, // 是否是分割线
            lineLabel: '扩展信息' // 分割线文字
        },
    ] as formItemTs[],
    formData: {
        input1: '',
        inputNum: '',
        inputPass: '',
        selId: '1',
        date1: '',
        date2: true,
        delivery: '',
        checkbox1: '',
        radio: '',
        lng: '',
        lat: '',
        curEmails: '',
        textarea1: '',
        slot1: ''
    },
})

const { formOption, formData } = toRefs(data)
</script>

<style lang="scss" scoped>
::v-deep(.el-form-item__content) {
    margin-left: 0 !important;
}
</style>

显示代码

获取输入节点实例

需要先获取fpiElForm实例,然后获取refInput属性,其包含所有的form内部节点的dom对象,相应的节点就是该节点对应的props的值,也就是: fpiElForm.refInput[props]

<template>
    <FpiElForm
        ref="dom"
        v-model="formData"
        :form-option="formOption"
    />
</template>

<script lang="ts" setup>
import type { formItemTs } from '@ued_fpi/element-plus-expand/es/src/fpi-el-form/types'

import { onMounted, reactive, ref, toRefs } from 'vue'
// 当然你可以直接通过设置type = 'text' 设置单项的类型为文本
const data = reactive({
    dom: ref(),
    formOption: [
        {
            label: '数字输入框',
            type: 'input',
            prop: 'inputNum',
            value: null,
            rules: 'unNull,number',
            inputProps: {
                clearable: true,
                placeholder: '测试',
            }
        },
        {
            label: '密码输入框',
            type: 'input',
            labelSlot: true,
            prop: 'inputPass',
            rules: 'unNull',
            inputProps: {
                showPassword: true,
                type: 'password',
                clearable: true,
                placeholder: '测试',
            }
        },
        {
            label: 'select输入',
            type: 'select',
            prop: 'selId',
            defaultSelect: 0,
            option: [],
            inputProps: {
                clearable: true,
            }
        },
    ] as formItemTs[],
    formData: {
        inputNum: 12314141,
        inputPass: '1241213',
        selId: 'shanghai',
    }
})
onMounted(() => {
    console.log('这是所有的input dom节点:', data.dom.refInput)
    console.log('对应的input的dom名称是prop的值:', data.dom.refInput.inputPass, 'dom')
    data.dom.refInput.inputPass.clear()
})
const { formOption, formData, dom } = toRefs(data)
</script>
显示代码

贡献者:

水产品-马佳辉

fpi-component