Vue配置化生成表单(个人笔记)

背景:为了避免编写重复的html, css, js代码(虽然一般情况下都是复制粘贴的),提高开发效率(其实是不想写)。配置化生成表单只需要我们写js对象就可以了。

知识点:Vue自带的component动态组件,is属性可以根据我们传入的参数解析成不同的组件。传入我们自定义的组件就会渲染成相应组件,传入el-input就会渲染成<el-input></el-input>组件。

封装schema-form组件

<template>
    <div>
        <el-form :model="form" ref="ruleForm" :rules="rules" :label-width="labelWidth" :class="direction==='vertical'?'normal_form':'flex_form'">
            <el-form-item v-for="item in options" :key="item.key" :prop="item.key" :label="item.label" :label-width="item.labelWidth || labelWidth" class="form_item">
                <!--提供一个插槽,提高扩展性-->
                <slot v-if="item.component === 'slot'" :name="item.slotName"></slot>
                <template v-else>
                    <component :is="item.component" v-model="form[item.key]" v-bind="item.props" v-on="item.listeners" :style="{width: item.width || '200px'}">
                        <template v-if="item.component === 'el-select'">
                            <el-option v-for="(subitem,index) in item.data" :key="index" :label="subitem.label" :value="subitem.value"></el-option>
                        </template>
                        <template v-else-if="item.component === 'el-checkbox-group'">
                            <el-checkbox
                                v-for="(subitem,index) in item.data"
                                :key="index"
                                :label="subitem.value"
                            >
                                {{ subitem.label }}
                            </el-checkbox>
                        </template>
                        <template v-else-if="item.component === 'el-radio-group'">
                            <el-radio
                                v-for="(subitem,index) in item.data"
                                :key="index"
                                :label="subitem.value"
                            >
                                {{ subitem.label }}
                            </el-radio>
                        </template>
                    </component>
                </template>
            </el-form-item>
        </el-form>
    </div>
</template>

el-select,el-checkbox-group,el-radio-group组件需要做特殊处理。

<script>
export default{
    props: {
        form: { // 表单绑定数据
            type: Object,
            default: {}
        },
        options: { // 表单项配置数据
            type: Array,
            default: []
        },
        rules: { // 表单验证规则
            type: Object,
            default: {}
        },
        labelWidth: { // label宽度
            type: String,
            default: '100px'
        },
        direction: { // 表单方向
            type: String,
            default: 'vertical'
        },
    },
    methods: {
        validate(callback) {
            this.$refs.ruleForm.validate(valid => {
                callback(valid)
            })
        },
        resetFields() {
            this.$refs.ruleForm.resetFields()
        }
    },
}
</script>
<style lang='scss' scoped>
    .flex_form {
        display: flex;
        flex-flow: wrap;
    }
</style>

使用组件

<template>
    <div>
        <schema-form ref="schemaForm" :form="form" :options="options" :rules="rules" labelWidth="120px" direction="vertical">
            <div slot="search">
                <el-button type="primary" @click="handleSubmit">搜索</el-button>
                <el-button @click="handleReset">重置</el-button>
            </div>
        </schema-form>
    </div>
</template>
<script>
import schemaForm from './components/schemaForm';
export default{
    components: { schemaForm },
    data() {
        return {
            form: {
                activity: [],
                age: '18'
            },
            options: [],
            rules: {
                name: [
                    { required: true, message: '请输入活动名称', trigger: 'blur' },
                ],
                age: [
                    { required: true, message: '请输入年龄', trigger: 'blur' },
                ],
            }
        }
    },
    created() {
        this.renderForm()
    },
    methods: {
        renderForm() {
            this.options = [
                {
                    component: 'el-input',
                    key: 'name',
                    label: '名字',
                    labelWidth: '120px',
                    props: {
                        placeholder: '请输入名字',
                        clearable: true
                    }
                },
                {
                    component: 'el-select',
                    key: 'age',
                    label: '年龄',
                    labelWidth: '120px',
                    props: {
                        placeholder: '请输入年龄',
                        clearable: true
                    },
                    data: [ // el-select, el-checkbox-group,el-radio-group 选项数据
                        {
                            label: '18',
                            value: '18'
                        },
                        {
                            label: '38',
                            value: '38'
                        }
                    ]
                },
                {
                    component: 'el-date-picker',
                    key: 'time',
                    label: '时间',
                    labelWidth: '120px',
                    width: '300px',
                    props: { // $attrs传给子组件的属性
                        placeholder: '请选择时间',
                        clearable: true,
                        type: 'daterange',
                        'range-separator': "至",
                        'start-placeholder': "开始日期",
                        'end-placeholder': "结束日期",
                        'value-format': 'yyyy-MM-dd HH:mm:ss'
                    },
                    listeners: { // $listeners传给子组件的事件
                        change: (e) => {
                            console.log("eeeeee", e)
                        }
                    }
                },
                {
                    component: 'slot',
                    slotName: 'search',
                }
            ]
        },
        handleSubmit() {
            this.$refs.schemaForm.validate(valid => {
                if(valid) {

                }
            })
        },
        handleReset() {
            this.$refs.schemaForm.resetFields()
        },
    },
}
</script>

options

参数 说明 默认值
component 组件名称
key 属性名称
label 标签文本
labelWidth 标签文本宽度 '100px'
width 表单元素宽度 '200px'
props 表单元素属性,根据element-ui提供属性
listeners 表单元素事件,根据element-ui提供事件
data 对el-select, el-checkbox-group,el-radio-group有效,选项数据

direction
表单方向,可选值:vertical和horizontal。

到目前写的例子还是很简单的配置,不能兼容各种场景,但是对于一般通用的场景还是值得一试的。后面可以根据业务场景进行不断的完善。(最后发现还是要写不少代码,感觉偷懒失败。)

参考文章:Vue2 Element Schema Form 配置式生成表单的实现

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容